Merge pull request #1438 from melex750/dev-cbot-fix-leaks
CBOT bug fixes and improved performancefix-squashed-planets
commit
efad9a4dae
|
@ -31,107 +31,100 @@
|
|||
namespace CBot
|
||||
{
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
CBotProgram* CBotCStack::m_prog = nullptr; // init the static variable
|
||||
CBotError CBotCStack::m_error = CBotNoErr;
|
||||
int CBotCStack::m_end = 0;
|
||||
CBotTypResult CBotCStack::m_retTyp = CBotTypResult(0);
|
||||
struct CBotCStack::Data
|
||||
{
|
||||
//! The program currently being compiled
|
||||
CBotProgram* prog = nullptr;
|
||||
//! The current error state of the compile stack
|
||||
CBotError error = CBotNoErr;
|
||||
int errEnd = 0;
|
||||
//! The return type of the function currently being compiled
|
||||
CBotTypResult retTyp = CBotTypResult(CBotTypVoid);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
CBotCStack::CBotCStack(CBotCStack* ppapa)
|
||||
{
|
||||
m_next = nullptr;
|
||||
m_prev = ppapa;
|
||||
|
||||
if (ppapa == nullptr)
|
||||
{
|
||||
m_error = CBotNoErr;
|
||||
m_start = 0;
|
||||
m_end = 0;
|
||||
m_data = new CBotCStack::Data;
|
||||
m_errStart = 0;
|
||||
m_bBlock = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_start = ppapa->m_start;
|
||||
m_data = ppapa->m_data;
|
||||
m_errStart = ppapa->m_errStart;
|
||||
m_bBlock = false;
|
||||
}
|
||||
|
||||
m_listVar = nullptr;
|
||||
m_var = nullptr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
CBotCStack::~CBotCStack()
|
||||
{
|
||||
if (m_next != nullptr) delete m_next;
|
||||
if (m_prev != nullptr) m_prev->m_next = nullptr; // removes chain
|
||||
|
||||
delete m_var;
|
||||
delete m_listVar;
|
||||
if (m_prev == nullptr) delete m_data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
CBotCStack* CBotCStack::TokenStack(CBotToken* pToken, bool bBlock)
|
||||
{
|
||||
if (m_next != nullptr) return m_next; // include on an existing stack
|
||||
if (m_next) return m_next.get(); // include on an existing stack
|
||||
|
||||
CBotCStack* p = new CBotCStack(this);
|
||||
m_next = p; // channel element
|
||||
p->m_bBlock = bBlock;
|
||||
m_next.reset(new CBotCStack(this));
|
||||
m_next->m_bBlock = bBlock;
|
||||
|
||||
if (pToken != nullptr) p->SetStartError(pToken->GetStart());
|
||||
if (pToken != nullptr) m_next->SetStartError(pToken->GetStart());
|
||||
|
||||
return p;
|
||||
return m_next.get();
|
||||
}
|
||||
|
||||
void CBotCStack::DeleteNext()
|
||||
{
|
||||
m_next.reset();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
CBotInstr* CBotCStack::Return(CBotInstr* inst, CBotCStack* pfils)
|
||||
{
|
||||
if ( pfils == this ) return inst;
|
||||
|
||||
if (m_var != nullptr) delete m_var; // value replaced?
|
||||
m_var = pfils->m_var; // result transmitted
|
||||
pfils->m_var = nullptr; // not to destroy the variable
|
||||
m_var = std::move(pfils->m_var); // result transmitted
|
||||
|
||||
if (m_error)
|
||||
if (m_data->error != CBotNoErr)
|
||||
{
|
||||
m_start = pfils->m_start; // retrieves the position of the error
|
||||
m_end = pfils->m_end;
|
||||
m_errStart = pfils->m_errStart; // retrieves the position of the error
|
||||
}
|
||||
|
||||
delete pfils;
|
||||
m_next.reset();
|
||||
return inst;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
CBotFunction* CBotCStack::ReturnFunc(CBotFunction* inst, CBotCStack* pfils)
|
||||
{
|
||||
if (m_var != nullptr) delete m_var; // value replaced?
|
||||
m_var = pfils->m_var; // result transmitted
|
||||
pfils->m_var = nullptr; // not to destroy the variable
|
||||
m_var = std::move(pfils->m_var); // result transmitted
|
||||
|
||||
if (m_error)
|
||||
if (m_data->error != CBotNoErr)
|
||||
{
|
||||
m_start = pfils->m_start; // retrieves the position of the error
|
||||
m_end = pfils->m_end;
|
||||
m_errStart = pfils->m_errStart; // retrieves the position of the error
|
||||
}
|
||||
|
||||
delete pfils;
|
||||
m_next.reset();
|
||||
return inst;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
CBotError CBotCStack::GetError(int& start, int& end)
|
||||
{
|
||||
start = m_start;
|
||||
end = m_end;
|
||||
return m_error;
|
||||
start = m_errStart;
|
||||
end = m_data->errEnd;
|
||||
return m_data->error;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
CBotError CBotCStack::GetError()
|
||||
{
|
||||
return m_error;
|
||||
return m_data->error;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -171,18 +164,13 @@ void CBotCStack::SetType(CBotTypResult& type)
|
|||
CBotVar* CBotCStack::FindVar(CBotToken* &pToken)
|
||||
{
|
||||
CBotCStack* p = this;
|
||||
std::string name = pToken->GetString();
|
||||
const auto& name = pToken->GetString();
|
||||
|
||||
while (p != nullptr)
|
||||
{
|
||||
CBotVar* pp = p->m_listVar;
|
||||
while ( pp != nullptr)
|
||||
if (p->m_bBlock) for (auto& var : p->m_listVar)
|
||||
{
|
||||
if (name == pp->GetName())
|
||||
{
|
||||
return pp;
|
||||
}
|
||||
pp = pp->m_next;
|
||||
if (name == var->GetName()) return var.get();
|
||||
}
|
||||
p = p->m_prev;
|
||||
}
|
||||
|
@ -211,39 +199,39 @@ CBotVar* CBotCStack::CopyVar(CBotToken& Token)
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool CBotCStack::IsOk()
|
||||
{
|
||||
return (m_error == 0);
|
||||
return (m_data->error == CBotNoErr);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void CBotCStack::SetStartError( int pos )
|
||||
{
|
||||
if ( m_error != 0) return; // does not change existing error
|
||||
m_start = pos;
|
||||
if (m_data->error != CBotNoErr) return; // does not change existing error
|
||||
m_errStart = pos;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void CBotCStack::SetError(CBotError n, int pos)
|
||||
{
|
||||
if ( n!= 0 && m_error != 0) return; // does not change existing error
|
||||
m_error = n;
|
||||
m_end = pos;
|
||||
if (n != CBotNoErr && m_data->error != CBotNoErr) return; // does not change existing error
|
||||
m_data->error = n;
|
||||
m_data->errEnd = pos;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void CBotCStack::SetError(CBotError n, CBotToken* p)
|
||||
{
|
||||
if (m_error) return; // does not change existing error
|
||||
m_error = n;
|
||||
m_start = p->GetStart();
|
||||
m_end = p->GetEnd();
|
||||
if (m_data->error != CBotNoErr) return; // does not change existing error
|
||||
m_data->error = n;
|
||||
m_errStart = p->GetStart();
|
||||
m_data->errEnd = p->GetEnd();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void CBotCStack::ResetError(CBotError n, int start, int end)
|
||||
{
|
||||
m_error = n;
|
||||
m_start = start;
|
||||
m_end = end;
|
||||
m_data->error = n;
|
||||
m_errStart = start;
|
||||
m_data->errEnd = end;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -261,48 +249,47 @@ bool CBotCStack::NextToken(CBotToken* &p)
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
void CBotCStack::SetProgram(CBotProgram* p)
|
||||
{
|
||||
m_prog = p;
|
||||
m_data->prog = p;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
CBotProgram* CBotCStack::GetProgram()
|
||||
{
|
||||
return m_prog;
|
||||
return m_data->prog;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void CBotCStack::SetRetType(CBotTypResult& type)
|
||||
{
|
||||
m_retTyp = type;
|
||||
m_data->retTyp = type;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
CBotTypResult CBotCStack::GetRetType()
|
||||
{
|
||||
return m_retTyp;
|
||||
return m_data->retTyp;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void CBotCStack::SetVar( CBotVar* var )
|
||||
{
|
||||
if (m_var) delete m_var; // replacement of a variable
|
||||
m_var = var;
|
||||
m_var.reset(var);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void CBotCStack::SetCopyVar( CBotVar* var )
|
||||
{
|
||||
if (m_var) delete m_var; // replacement of a variable
|
||||
m_var.reset();
|
||||
|
||||
if ( var == nullptr ) return;
|
||||
m_var = CBotVar::Create("", var->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC));
|
||||
m_var.reset(CBotVar::Create("", var->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC)));
|
||||
m_var->Copy( var );
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
CBotVar* CBotCStack::GetVar()
|
||||
{
|
||||
return m_var;
|
||||
return m_var.get();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -310,15 +297,12 @@ void CBotCStack::AddVar(CBotVar* pVar)
|
|||
{
|
||||
CBotCStack* p = this;
|
||||
|
||||
// returns to the father element
|
||||
// find the level of the current block
|
||||
while (p != nullptr && p->m_bBlock == 0) p = p->m_prev;
|
||||
|
||||
if ( p == nullptr ) return;
|
||||
if (p == nullptr || pVar == nullptr) return;
|
||||
|
||||
CBotVar** pp = &p->m_listVar;
|
||||
while ( *pp != nullptr ) pp = &(*pp)->m_next;
|
||||
|
||||
*pp = pVar; // added after
|
||||
p->m_listVar.emplace_back(pVar);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -369,19 +353,14 @@ void CBotCStack::CreateMemberVars(CBotClass* pClass, bool setDefined)
|
|||
bool CBotCStack::CheckVarLocal(CBotToken* &pToken)
|
||||
{
|
||||
CBotCStack* p = this;
|
||||
std::string name = pToken->GetString();
|
||||
const auto& name = pToken->GetString();
|
||||
|
||||
while (p != nullptr)
|
||||
// find the level of the current block
|
||||
while (p != nullptr && p->m_bBlock == 0) p = p->m_prev;
|
||||
|
||||
if (p != nullptr) for (auto& var : p->m_listVar)
|
||||
{
|
||||
CBotVar* pp = p->m_listVar;
|
||||
while ( pp != nullptr)
|
||||
{
|
||||
if (name == pp->GetName())
|
||||
return true;
|
||||
pp = pp->m_next;
|
||||
}
|
||||
if ( p->m_bBlock ) return false;
|
||||
p = p->m_prev;
|
||||
if (name == var->GetName()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -392,10 +371,10 @@ CBotTypResult CBotCStack::CompileCall(CBotToken* &p, CBotVar** ppVars, long& nId
|
|||
nIdent = 0;
|
||||
CBotTypResult val(-1);
|
||||
|
||||
val = m_prog->GetExternalCalls()->CompileCall(p, nullptr, ppVars, this);
|
||||
val = GetProgram()->GetExternalCalls()->CompileCall(p, nullptr, ppVars, this);
|
||||
if (val.GetType() < 0)
|
||||
{
|
||||
val = CBotFunction::CompileCall(p->GetString(), ppVars, nIdent, m_prog);
|
||||
val = CBotFunction::CompileCall(p->GetString(), ppVars, nIdent, GetProgram());
|
||||
if ( val.GetType() < 0 )
|
||||
{
|
||||
// pVar = nullptr; // the error is not on a particular parameter
|
||||
|
@ -410,13 +389,13 @@ CBotTypResult CBotCStack::CompileCall(CBotToken* &p, CBotVar** ppVars, long& nId
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool CBotCStack::CheckCall(CBotToken* &pToken, CBotDefParam* pParam, const std::string& className)
|
||||
{
|
||||
std::string name = pToken->GetString();
|
||||
const auto& name = pToken->GetString();
|
||||
|
||||
if ( m_prog->GetExternalCalls()->CheckCall(name) ) return true;
|
||||
if ( GetProgram()->GetExternalCalls()->CheckCall(name) ) return true;
|
||||
|
||||
for (CBotFunction* pp : m_prog->GetFunctions())
|
||||
for (CBotFunction* pp : GetProgram()->GetFunctions())
|
||||
{
|
||||
if ( pToken->GetString() == pp->GetName() )
|
||||
if ( name == pp->GetName() )
|
||||
{
|
||||
// ignore methods for a different class
|
||||
if ( className != pp->GetClassName() )
|
||||
|
@ -429,7 +408,7 @@ bool CBotCStack::CheckCall(CBotToken* &pToken, CBotDefParam* pParam, const std::
|
|||
|
||||
for (CBotFunction* pp : CBotFunction::m_publicFunctions)
|
||||
{
|
||||
if ( pToken->GetString() == pp->GetName() )
|
||||
if ( name == pp->GetName() )
|
||||
{
|
||||
// ignore methods for a different class
|
||||
if ( className != pp->GetClassName() )
|
||||
|
@ -443,4 +422,4 @@ bool CBotCStack::CheckCall(CBotToken* &pToken, CBotDefParam* pParam, const std::
|
|||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace CBot
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
#include "CBot/CBotVar/CBotVar.h"
|
||||
#include "CBot/CBotProgram.h"
|
||||
|
||||
#include <list>
|
||||
#include <memory>
|
||||
|
||||
namespace CBot
|
||||
{
|
||||
|
||||
|
@ -157,6 +160,11 @@ public:
|
|||
*/
|
||||
CBotCStack* TokenStack(CBotToken* pToken = nullptr, bool bBlock = false);
|
||||
|
||||
/*!
|
||||
* \brief Deletes all subsequent stack frames created by TokenStack.
|
||||
*/
|
||||
void DeleteNext();
|
||||
|
||||
/*!
|
||||
* \brief Return Transmits the result upper.
|
||||
* \param p
|
||||
|
@ -269,21 +277,20 @@ public:
|
|||
bool NextToken(CBotToken* &p);
|
||||
|
||||
private:
|
||||
CBotCStack* m_next;
|
||||
std::unique_ptr<CBotCStack> m_next;
|
||||
CBotCStack* m_prev;
|
||||
|
||||
static CBotError m_error;
|
||||
static int m_end;
|
||||
int m_start;
|
||||
int m_errStart = 0;
|
||||
|
||||
struct Data;
|
||||
|
||||
CBotCStack::Data* m_data;
|
||||
|
||||
//! Result of the operations.
|
||||
CBotVar* m_var;
|
||||
std::unique_ptr<CBotVar> m_var;
|
||||
//! Is part of a block (variables are local to this block).
|
||||
bool m_bBlock;
|
||||
CBotVar* m_listVar;
|
||||
//! List of compiled functions.
|
||||
static CBotProgram* m_prog;
|
||||
static CBotTypResult m_retTyp;
|
||||
std::list<std::unique_ptr<CBotVar>> m_listVar;
|
||||
};
|
||||
|
||||
} // namespace CBot
|
||||
|
|
|
@ -605,8 +605,8 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
|
|||
// return a method precompiled in pass 1
|
||||
CBotCStack* pStk = pStack->TokenStack(nullptr, true);
|
||||
CBotDefParam* params = CBotDefParam::Compile(p, pStk );
|
||||
delete pStk;
|
||||
std::list<CBotFunction*>::iterator pfIter = std::find_if(m_pMethod.begin(), m_pMethod.end(), [&pp, ¶ms](CBotFunction* x)
|
||||
pStack->DeleteNext();
|
||||
auto pfIter = std::find_if(m_pMethod.begin(), m_pMethod.end(), [&pp, ¶ms](CBotFunction* x)
|
||||
{
|
||||
return x->GetName() == pp && x->CheckParam( params );
|
||||
});
|
||||
|
@ -626,7 +626,7 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
|
|||
f->m_pProg = pStack->GetProgram();
|
||||
f->m_bSynchro = bSynchro;
|
||||
}
|
||||
pStack->Return(nullptr, pile);
|
||||
pStack->DeleteNext();
|
||||
}
|
||||
|
||||
return pStack->IsOk();
|
||||
|
|
|
@ -94,7 +94,7 @@ CBotDefParam* CBotDefParam::Compile(CBotToken* &p, CBotCStack* pStack)
|
|||
prevHasDefault = true;
|
||||
}
|
||||
else pStack->SetError(CBotErrNoExpression, p);
|
||||
delete pStk;
|
||||
pStack->DeleteNext();
|
||||
}
|
||||
else
|
||||
if (prevHasDefault) pStack->SetError(CBotErrDefaultValue, p->GetPrev());
|
||||
|
@ -137,6 +137,7 @@ bool CBotDefParam::Execute(CBotVar** ppVars, CBotStack* &pj)
|
|||
while ( p != nullptr )
|
||||
{
|
||||
pile = pile->AddStack();
|
||||
if (pile->StackOver()) return pj->Return(pile);
|
||||
if (pile->GetState() == 1) // already done?
|
||||
{
|
||||
if (ppVars != nullptr && ppVars[i] != nullptr) ++i;
|
||||
|
|
|
@ -82,19 +82,23 @@ int CBotExternalCallList::DoCall(CBotToken* token, CBotVar* thisVar, CBotVar** p
|
|||
|
||||
CBotExternalCall* pt = m_list[token->GetString()].get();
|
||||
|
||||
if (pStack->IsCallFinished()) return true;
|
||||
CBotStack* pile = pStack->AddStackExternalCall(pt);
|
||||
if (thisVar == nullptr && pStack->IsCallFinished()) return true; // only for non-method external call
|
||||
|
||||
// lists the parameters depending on the contents of the stack (pStackVar)
|
||||
CBotVar* pVar = MakeListVars(ppVar, true);
|
||||
// if this is a method call we need to use AddStack()
|
||||
CBotStack* pile = (thisVar != nullptr) ? pStack->AddStack() : pStack->AddStackExternalCall(pt);
|
||||
|
||||
// creates a variable to the result
|
||||
CBotVar* pResult = rettype.Eq(CBotTypVoid) ? nullptr : CBotVar::Create("", rettype);
|
||||
if (pile->GetState() == 0) // the first time?
|
||||
{
|
||||
// lists the parameters depending on the contents of the stack
|
||||
CBotVar* pVar = MakeListVars(ppVar, true);
|
||||
pile->SetVar(pVar);
|
||||
|
||||
pile->SetVar(pVar);
|
||||
|
||||
CBotStack* pile2 = pile->AddStack();
|
||||
pile2->SetVar(pResult);
|
||||
CBotStack* pile2 = pile->AddStack();
|
||||
// creates a variable to the result
|
||||
CBotVar* pResult = rettype.Eq(CBotTypVoid) ? nullptr : CBotVar::Create("", rettype);
|
||||
pile2->SetVar(pResult);
|
||||
pile->IncState(); // increment state to mark this step done
|
||||
}
|
||||
|
||||
pile->SetError(CBotNoErr, token); // save token for the position in case of error
|
||||
return pt->Run(thisVar, pStack);
|
||||
|
@ -107,7 +111,8 @@ bool CBotExternalCallList::RestoreCall(CBotToken* token, CBotVar* thisVar, CBotV
|
|||
|
||||
CBotExternalCall* pt = m_list[token->GetString()].get();
|
||||
|
||||
CBotStack* pile = pStack->RestoreStackEOX(pt);
|
||||
// if this is a method call we need to use RestoreStack()
|
||||
CBotStack* pile = (thisVar != nullptr) ? pStack->RestoreStack() : pStack->RestoreStackEOX(pt);
|
||||
if (pile == nullptr) return true;
|
||||
|
||||
pile->RestoreStack();
|
||||
|
@ -163,8 +168,7 @@ bool CBotExternalCallDefault::Run(CBotVar* thisVar, CBotStack* pStack)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (result != nullptr) pStack->SetCopyVar(result);
|
||||
|
||||
pStack->Return(pile2); // return 'result' and clear extra stack
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -187,8 +191,8 @@ CBotTypResult CBotExternalCallClass::Compile(CBotVar* thisVar, CBotVar* args, vo
|
|||
|
||||
bool CBotExternalCallClass::Run(CBotVar* thisVar, CBotStack* pStack)
|
||||
{
|
||||
if (pStack->IsCallFinished()) return true;
|
||||
CBotStack* pile = pStack->AddStackExternalCall(this);
|
||||
assert(thisVar != nullptr);
|
||||
CBotStack* pile = pStack->AddStack();
|
||||
CBotVar* args = pile->GetVar();
|
||||
|
||||
CBotStack* pile2 = pile->AddStack();
|
||||
|
@ -207,9 +211,8 @@ bool CBotExternalCallClass::Run(CBotVar* thisVar, CBotStack* pStack)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (result != nullptr) pStack->SetCopyVar(result);
|
||||
|
||||
pStack->Return(pile2); // return 'result' and clear extra stack
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace CBot
|
||||
|
|
|
@ -135,7 +135,7 @@ CBotInstr* CBotDefClass::Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* p
|
|||
// the constructor is there?
|
||||
// std::string noname;
|
||||
CBotTypResult r = pClass->CompileMethode(&token, var, ppVars, pStk, inst->m_nMethodeIdent);
|
||||
delete pStk->TokenStack(); // releases the supplement stack
|
||||
pStk->DeleteNext(); // releases the supplement stack
|
||||
int typ = r.GetType();
|
||||
|
||||
if (typ == CBotErrUndefCall)
|
||||
|
@ -160,7 +160,7 @@ CBotInstr* CBotDefClass::Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* p
|
|||
if (nullptr != (inst->m_exprRetVar = CBotExprRetVar::Compile(p, pStk, true)))
|
||||
{
|
||||
inst->m_exprRetVar->SetToken(vartoken);
|
||||
delete pStk->TokenStack();
|
||||
pStk->DeleteNext();
|
||||
}
|
||||
pStk->SetVar(nullptr);
|
||||
|
||||
|
@ -360,6 +360,7 @@ bool CBotDefClass::Execute(CBotStack* &pj)
|
|||
if ( p != nullptr) while ( true )
|
||||
{
|
||||
pile2 = pile2->AddStack(); // place on the stack for the results
|
||||
if (pile2->StackOver()) return pj->Return(pile2);
|
||||
if ( pile2->GetState() == 0 )
|
||||
{
|
||||
if (!p->Execute(pile2)) return false; // interrupted here?
|
||||
|
|
|
@ -445,7 +445,7 @@ bool CBotFunction::Execute(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance)
|
|||
pile->IncState();
|
||||
}
|
||||
|
||||
if ( !m_block->Execute(pile) )
|
||||
if (!pile->GetRetVar(m_block->Execute(pile)))
|
||||
{
|
||||
if ( pile->GetError() < 0 )
|
||||
pile->SetError( CBotNoErr );
|
||||
|
|
|
@ -78,12 +78,12 @@ CBotInstr* CBotInstrCall::Compile(CBotToken* &p, CBotCStack* pStack)
|
|||
{
|
||||
// if (pVar2!=nullptr) pp = pVar2->RetToken();
|
||||
pStack->SetError( static_cast<CBotError>(inst->m_typRes.GetType()), pp );
|
||||
delete pStack->TokenStack();
|
||||
pStack->DeleteNext();
|
||||
delete inst;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
delete pStack->TokenStack();
|
||||
pStack->DeleteNext();
|
||||
if ( inst->m_typRes.GetType() > 0 )
|
||||
{
|
||||
CBotVar* pRes = CBotVar::Create("", inst->m_typRes);
|
||||
|
@ -94,7 +94,7 @@ CBotInstr* CBotInstrCall::Compile(CBotToken* &p, CBotCStack* pStack)
|
|||
if (nullptr != (inst->m_exprRetVar = CBotExprRetVar::Compile(p, pStack)))
|
||||
{
|
||||
inst->m_exprRetVar->SetToken(&inst->m_token);
|
||||
delete pStack->TokenStack();
|
||||
pStack->DeleteNext();
|
||||
}
|
||||
if ( !pStack->IsOk() )
|
||||
{
|
||||
|
@ -105,7 +105,7 @@ CBotInstr* CBotInstrCall::Compile(CBotToken* &p, CBotCStack* pStack)
|
|||
return inst;
|
||||
}
|
||||
p = pp;
|
||||
delete pStack->TokenStack();
|
||||
pStack->DeleteNext();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -138,6 +138,7 @@ bool CBotInstrCall::Execute(CBotStack* &pj)
|
|||
if ( p != nullptr) while ( true )
|
||||
{
|
||||
pile = pile->AddStack(); // place on the stack for the results
|
||||
if (pile->StackOver()) return pj->Return(pile);
|
||||
if ( pile->GetState() == 0 )
|
||||
{
|
||||
if (!p->Execute(pile)) return false; // interrupted here?
|
||||
|
|
|
@ -70,7 +70,7 @@ CBotInstr* CBotInstrMethode::Compile(CBotToken* &p, CBotCStack* pStack, CBotVar*
|
|||
CBotClass* pClass = var->GetClass(); // pointer to the class
|
||||
inst->m_className = pClass->GetName(); // name of the class
|
||||
CBotTypResult r = pClass->CompileMethode(pp, var, ppVars, pStack, inst->m_MethodeIdent);
|
||||
delete pStack->TokenStack(); // release parameters on the stack
|
||||
pStack->DeleteNext(); // release parameters on the stack
|
||||
inst->m_typRes = r;
|
||||
|
||||
if (inst->m_typRes.GetType() > 20)
|
||||
|
@ -95,7 +95,7 @@ CBotInstr* CBotInstrMethode::Compile(CBotToken* &p, CBotCStack* pStack, CBotVar*
|
|||
if (nullptr != (inst->m_exprRetVar = CBotExprRetVar::Compile(p, pStack, bMethodChain)))
|
||||
{
|
||||
inst->m_exprRetVar->SetToken(pp);
|
||||
delete pStack->TokenStack();
|
||||
pStack->DeleteNext();
|
||||
}
|
||||
|
||||
if ( pStack->IsOk() )
|
||||
|
@ -164,6 +164,7 @@ bool CBotInstrMethode::ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* pre
|
|||
}
|
||||
ppVars[i++] = pile2->GetVar(); // construct the list of pointers
|
||||
pile2 = pile2->AddStack(); // space on the stack for the result
|
||||
if (pile2->StackOver()) return pj->Return(pile2);
|
||||
p = p->GetNext();
|
||||
if ( p == nullptr) break;
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ CBotInstr* CompileParams(CBotToken* &p, CBotCStack* pStack, CBotVar** ppVars)
|
|||
{
|
||||
if (pile->GetTypResult().Eq(99))
|
||||
{
|
||||
delete pStack->TokenStack();
|
||||
pStack->DeleteNext();
|
||||
pStack->SetError(CBotErrVoid, p->GetStart());
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ CBotInstr* CompileParams(CBotToken* &p, CBotCStack* pStack, CBotVar** ppVars)
|
|||
}
|
||||
|
||||
pStack->SetError(CBotErrClosePar, p->GetStart());
|
||||
delete pStack->TokenStack();
|
||||
pStack->DeleteNext();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ CBotInstr* CBotNew::Compile(CBotToken* &p, CBotCStack* pStack)
|
|||
|
||||
// constructor exist?
|
||||
CBotTypResult r = pClass->CompileMethode(&inst->m_vartoken, pVar, ppVars, pStk, inst->m_nMethodeIdent);
|
||||
delete pStk->TokenStack(); // release extra stack
|
||||
pStk->DeleteNext(); // release extra stack
|
||||
int typ = r.GetType();
|
||||
|
||||
// if there is no constructor, and no parameters either, it's ok
|
||||
|
@ -115,7 +115,7 @@ CBotInstr* CBotNew::Compile(CBotToken* &p, CBotCStack* pStack)
|
|||
if (nullptr != (inst->m_exprRetVar = CBotExprRetVar::Compile(p, pStk, true)))
|
||||
{
|
||||
inst->m_exprRetVar->SetToken(pp);
|
||||
delete pStk->TokenStack();
|
||||
pStk->DeleteNext();
|
||||
}
|
||||
|
||||
if (pStack->IsOk())
|
||||
|
@ -189,6 +189,7 @@ bool CBotNew::Execute(CBotStack* &pj)
|
|||
if (p != nullptr) while ( true)
|
||||
{
|
||||
pile2 = pile2->AddStack(); // space on the stack for the result
|
||||
if (pile2->StackOver()) return pj->Return(pile2);
|
||||
if (pile2->GetState() == 0)
|
||||
{
|
||||
if (!p->Execute(pile2)) return false; // interrupted here?
|
||||
|
|
|
@ -71,7 +71,7 @@ CBotInstr* CBotSwitch::Compile(CBotToken* &p, CBotCStack* pStack)
|
|||
{
|
||||
if ( p->GetType() == ID_CASE || p->GetType() == ID_DEFAULT)
|
||||
{
|
||||
delete pStk2;
|
||||
pStk->DeleteNext();
|
||||
pStk2 = pStk->TokenStack(p, true); // some space for a stack, plz
|
||||
|
||||
caseInst = static_cast<CBotCase*>(CBotCase::Compile(p, pStk2, inst->m_labels));
|
||||
|
|
|
@ -357,6 +357,7 @@ bool CBotTwoOpExpr::Execute(CBotStack* &pStack)
|
|||
|
||||
CBotStack* pStk2 = pStk1->AddStack(); // adds an item to the stack
|
||||
// or return in case of recovery
|
||||
if (pStk2->StackOver()) return pStack->Return(pStk2);
|
||||
|
||||
// 2nd state, evalute right operand
|
||||
if ( pStk2->GetState() == 0 )
|
||||
|
@ -514,7 +515,6 @@ bool CBotTwoOpExpr::Execute(CBotStack* &pStack)
|
|||
pStk2->SetVar(result); // puts the result on the stack
|
||||
if ( err ) pStk2->SetError(err, &m_token); // and the possible error (division by zero)
|
||||
|
||||
// pStk1->Return(pStk2); // releases the stack
|
||||
return pStack->Return(pStk2); // transmits the result
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
namespace CBot
|
||||
{
|
||||
|
||||
CBotExternalCallList* CBotProgram::m_externalCalls = new CBotExternalCallList();
|
||||
std::unique_ptr<CBotExternalCallList> CBotProgram::m_externalCalls;
|
||||
|
||||
CBotProgram::CBotProgram()
|
||||
{
|
||||
|
@ -243,13 +243,6 @@ CBotVar* CBotProgram::GetStackVars(std::string& functionName, int level)
|
|||
return m_stack->GetStackVars(functionName, level);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void CBotProgram::SetTimer(int n)
|
||||
{
|
||||
CBotStack::SetTimer( n );
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
CBotError CBotProgram::GetError()
|
||||
{
|
||||
return m_error;
|
||||
|
@ -395,6 +388,8 @@ int CBotProgram::GetVersion()
|
|||
|
||||
void CBotProgram::Init()
|
||||
{
|
||||
m_externalCalls.reset(new CBotExternalCallList);
|
||||
|
||||
CBotProgram::DefineNum("CBotErrZeroDiv", CBotErrZeroDiv); // division by zero
|
||||
CBotProgram::DefineNum("CBotErrNotInit", CBotErrNotInit); // uninitialized variable
|
||||
CBotProgram::DefineNum("CBotErrBadThrow", CBotErrBadThrow); // throw a negative value
|
||||
|
@ -420,9 +415,10 @@ void CBotProgram::Free()
|
|||
CBotToken::ClearDefineNum();
|
||||
m_externalCalls->Clear();
|
||||
CBotClass::ClearPublic();
|
||||
m_externalCalls.reset();
|
||||
}
|
||||
|
||||
CBotExternalCallList* CBotProgram::GetExternalCalls()
|
||||
const std::unique_ptr<CBotExternalCallList>& CBotProgram::GetExternalCalls()
|
||||
{
|
||||
return m_externalCalls;
|
||||
}
|
||||
|
|
|
@ -19,11 +19,12 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "CBot/CBotTypResult.h"
|
||||
#include "CBot/CBotEnums.h"
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace CBot
|
||||
{
|
||||
|
@ -31,6 +32,7 @@ namespace CBot
|
|||
class CBotFunction;
|
||||
class CBotClass;
|
||||
class CBotStack;
|
||||
class CBotTypResult;
|
||||
class CBotVar;
|
||||
class CBotExternalCallList;
|
||||
|
||||
|
@ -200,14 +202,6 @@ public:
|
|||
*/
|
||||
void Stop();
|
||||
|
||||
/**
|
||||
* \brief Sets the number of steps (parts of instructions) to execute in Run() before suspending the program execution
|
||||
* \param n new timer value
|
||||
*
|
||||
* FIXME: Seems to be currently kind of broken (see issue #410)
|
||||
*/
|
||||
static void SetTimer(int n);
|
||||
|
||||
/**
|
||||
* \brief Add a function that can be called from CBot
|
||||
*
|
||||
|
@ -335,11 +329,11 @@ public:
|
|||
/**
|
||||
* \brief Returns static list of all registered external calls
|
||||
*/
|
||||
static CBotExternalCallList* GetExternalCalls();
|
||||
static const std::unique_ptr<CBotExternalCallList>& GetExternalCalls();
|
||||
|
||||
private:
|
||||
//! All external calls
|
||||
static CBotExternalCallList* m_externalCalls;
|
||||
static std::unique_ptr<CBotExternalCallList> m_externalCalls;
|
||||
//! All user-defined functions
|
||||
std::list<CBotFunction*> m_functions{};
|
||||
//! The entry point function
|
||||
|
|
|
@ -39,16 +39,24 @@ namespace CBot
|
|||
|
||||
const int DEFAULT_TIMER = 100;
|
||||
|
||||
int CBotStack::m_initimer = DEFAULT_TIMER;
|
||||
int CBotStack::m_timer = 0;
|
||||
CBotVar* CBotStack::m_retvar = nullptr;
|
||||
CBotError CBotStack::m_error = CBotNoErr;
|
||||
int CBotStack::m_start = 0;
|
||||
int CBotStack::m_end = 0;
|
||||
std::string CBotStack::m_labelBreak="";
|
||||
void* CBotStack::m_pUser = nullptr;
|
||||
struct CBotStack::Data
|
||||
{
|
||||
int initimer = DEFAULT_TIMER;
|
||||
int timer = 0;
|
||||
|
||||
CBotError error = CBotNoErr;
|
||||
int errStart = 0;
|
||||
int errEnd = 0;
|
||||
|
||||
std::string labelBreak = "";
|
||||
|
||||
CBotProgram* baseProg = nullptr;
|
||||
CBotStack* topStack = nullptr;
|
||||
void* pUser = nullptr;
|
||||
|
||||
std::unique_ptr<CBotVar> retvar;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
CBotStack* CBotStack::AllocateStack()
|
||||
{
|
||||
CBotStack* p;
|
||||
|
@ -73,7 +81,8 @@ CBotStack* CBotStack::AllocateStack()
|
|||
pp ++;
|
||||
}
|
||||
|
||||
m_error = CBotNoErr; // avoids deadlocks because m_error is static
|
||||
p->m_data = new CBotStack::Data;
|
||||
p->m_data->topStack = p;
|
||||
return p;
|
||||
}
|
||||
|
||||
|
@ -97,6 +106,7 @@ void CBotStack::Delete()
|
|||
|
||||
CBotStack* p = m_prev;
|
||||
bool bOver = m_bOver;
|
||||
if ( m_prev == nullptr ) delete m_data;
|
||||
|
||||
// clears the freed block
|
||||
memset(this, 0, sizeof(CBotStack));
|
||||
|
@ -123,6 +133,7 @@ CBotStack* CBotStack::AddStack(CBotInstr* instr, BlockVisibilityType bBlock)
|
|||
while ( p->m_prev != nullptr );
|
||||
|
||||
m_next = p; // chain an element
|
||||
p->m_data = m_data;
|
||||
p->m_block = bBlock;
|
||||
p->m_instr = instr;
|
||||
p->m_prog = m_prog;
|
||||
|
@ -166,6 +177,7 @@ CBotStack* CBotStack::AddStack2(BlockVisibilityType bBlock)
|
|||
while ( p->m_prev != nullptr );
|
||||
|
||||
m_next2 = p; // chain an element
|
||||
p->m_data = m_data;
|
||||
p->m_prev = this;
|
||||
p->m_block = bBlock;
|
||||
p->m_prog = m_prog;
|
||||
|
@ -220,18 +232,32 @@ bool CBotStack::ReturnKeep(CBotStack* pfils)
|
|||
bool CBotStack::StackOver()
|
||||
{
|
||||
if (!m_bOver) return false;
|
||||
m_error = CBotErrStackOver;
|
||||
m_data->error = CBotErrStackOver;
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
CBotError CBotStack::GetError(int& start, int& end)
|
||||
{
|
||||
start = m_data->errStart;
|
||||
end = m_data->errEnd;
|
||||
return m_data->error;
|
||||
}
|
||||
|
||||
CBotError CBotStack::GetError()
|
||||
{
|
||||
return m_data->error;
|
||||
}
|
||||
|
||||
bool CBotStack::IsOk()
|
||||
{
|
||||
return m_data->error == CBotNoErr;
|
||||
}
|
||||
|
||||
void CBotStack::Reset()
|
||||
{
|
||||
m_timer = m_initimer; // resets the timer
|
||||
m_error = CBotNoErr;
|
||||
// m_start = 0;
|
||||
// m_end = 0;
|
||||
m_labelBreak.clear();
|
||||
m_data->timer = m_data->initimer; // resets the timer
|
||||
m_data->error = CBotNoErr;
|
||||
m_data->labelBreak.clear();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -258,35 +284,35 @@ CBotStack* CBotStack::RestoreStackEOX(CBotExternalCall* instr)
|
|||
// routine for execution step by step
|
||||
bool CBotStack::IfStep()
|
||||
{
|
||||
if ( m_initimer > 0 || m_step++ > 0 ) return false;
|
||||
if (m_data->initimer > 0 || m_step++ > 0) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool CBotStack::BreakReturn(CBotStack* pfils, const std::string& name)
|
||||
{
|
||||
if ( m_error>=0 ) return false; // normal output
|
||||
if ( m_error==CBotError(-3) ) return false; // normal output (return current)
|
||||
if (m_data->error >= CBotNoErr) return false; // normal output
|
||||
if (m_data->error == CBotError(-3)) return false; // normal output (return current)
|
||||
|
||||
if (!m_labelBreak.empty() && (name.empty() || m_labelBreak != name))
|
||||
if (!m_data->labelBreak.empty() && (name.empty() || m_data->labelBreak != name))
|
||||
return false; // it's not for me
|
||||
|
||||
m_error = CBotNoErr;
|
||||
m_labelBreak.clear();
|
||||
m_data->error = CBotNoErr;
|
||||
m_data->labelBreak.clear();
|
||||
return Return(pfils);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool CBotStack::IfContinue(int state, const std::string& name)
|
||||
{
|
||||
if ( m_error != CBotError(-2) ) return false;
|
||||
if (m_data->error != CBotError(-2)) return false;
|
||||
|
||||
if (!m_labelBreak.empty() && (name.empty() || m_labelBreak != name))
|
||||
if (!m_data->labelBreak.empty() && (name.empty() || m_data->labelBreak != name))
|
||||
return false; // it's not for me
|
||||
|
||||
m_state = state; // where again?
|
||||
m_error = CBotNoErr;
|
||||
m_labelBreak.clear();
|
||||
m_data->error = CBotNoErr;
|
||||
m_data->labelBreak.clear();
|
||||
if (m_next != nullptr) m_next->Delete(); // purge above stack
|
||||
return true;
|
||||
}
|
||||
|
@ -294,11 +320,11 @@ bool CBotStack::IfContinue(int state, const std::string& name)
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
void CBotStack::SetBreak(int val, const std::string& name)
|
||||
{
|
||||
m_error = static_cast<CBotError>(-val); // reacts as an Exception
|
||||
m_labelBreak = name;
|
||||
m_data->error = static_cast<CBotError>(-val); // reacts as an Exception
|
||||
m_data->labelBreak = name;
|
||||
if (val == 3) // for a return
|
||||
{
|
||||
m_retvar = m_var;
|
||||
m_data->retvar.reset(m_var);
|
||||
m_var = nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -307,12 +333,11 @@ void CBotStack::SetBreak(int val, const std::string& name)
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool CBotStack::GetRetVar(bool bRet)
|
||||
{
|
||||
if (m_error == CBotError(-3))
|
||||
if (m_data->error == CBotError(-3))
|
||||
{
|
||||
if ( m_var ) delete m_var;
|
||||
m_var = m_retvar;
|
||||
m_retvar = nullptr;
|
||||
m_error = CBotNoErr;
|
||||
m_var = m_data->retvar.release();
|
||||
m_data->error = CBotNoErr;
|
||||
return true;
|
||||
}
|
||||
return bRet; // interrupted by something other than return
|
||||
|
@ -322,7 +347,7 @@ bool CBotStack::GetRetVar(bool bRet)
|
|||
CBotVar* CBotStack::FindVar(CBotToken*& pToken, bool bUpdate)
|
||||
{
|
||||
CBotStack* p = this;
|
||||
std::string name = pToken->GetString();
|
||||
const auto& name = pToken->GetString();
|
||||
|
||||
while (p != nullptr)
|
||||
{
|
||||
|
@ -332,7 +357,7 @@ CBotVar* CBotStack::FindVar(CBotToken*& pToken, bool bUpdate)
|
|||
if (pp->GetName() == name)
|
||||
{
|
||||
if ( bUpdate )
|
||||
pp->Update(m_pUser);
|
||||
pp->Update(m_data->pUser);
|
||||
|
||||
return pp;
|
||||
}
|
||||
|
@ -375,7 +400,7 @@ CBotVar* CBotStack::FindVar(long ident, bool bUpdate)
|
|||
if (pp->GetUniqNum() == ident)
|
||||
{
|
||||
if ( bUpdate )
|
||||
pp->Update(m_pUser);
|
||||
pp->Update(m_data->pUser);
|
||||
|
||||
return pp;
|
||||
}
|
||||
|
@ -410,8 +435,8 @@ bool CBotStack::SetState(int n, int limite)
|
|||
{
|
||||
m_state = n;
|
||||
|
||||
m_timer--; // decrement the timer
|
||||
return ( m_timer > limite ); // interrupted if timer pass
|
||||
m_data->timer--; // decrement the timer
|
||||
return (m_data->timer > limite); // interrupted if timer pass
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -419,46 +444,46 @@ bool CBotStack::IncState(int limite)
|
|||
{
|
||||
m_state++;
|
||||
|
||||
m_timer--; // decrement the timer
|
||||
return ( m_timer > limite ); // interrupted if timer pass
|
||||
m_data->timer--; // decrement the timer
|
||||
return (m_data->timer > limite); // interrupted if timer pass
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void CBotStack::SetError(CBotError n, CBotToken* token)
|
||||
{
|
||||
if (n != CBotNoErr && m_error != CBotNoErr) return; // does not change existing error
|
||||
m_error = n;
|
||||
if (n != CBotNoErr && m_data->error != CBotNoErr) return; // does not change existing error
|
||||
m_data->error = n;
|
||||
if (token != nullptr)
|
||||
{
|
||||
m_start = token->GetStart();
|
||||
m_end = token->GetEnd();
|
||||
m_data->errStart = token->GetStart();
|
||||
m_data->errEnd = token->GetEnd();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void CBotStack::ResetError(CBotError n, int start, int end)
|
||||
{
|
||||
m_error = n;
|
||||
m_start = start;
|
||||
m_end = end;
|
||||
m_data->error = n;
|
||||
m_data->errStart = start;
|
||||
m_data->errEnd = end;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void CBotStack::SetPosError(CBotToken* token)
|
||||
{
|
||||
m_start = token->GetStart();
|
||||
m_end = token->GetEnd();
|
||||
m_data->errStart = token->GetStart();
|
||||
m_data->errEnd = token->GetEnd();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void CBotStack::SetTimer(int n)
|
||||
{
|
||||
m_initimer = n;
|
||||
m_data->initimer = n;
|
||||
}
|
||||
|
||||
int CBotStack::GetTimer()
|
||||
{
|
||||
return m_initimer;
|
||||
return m_data->initimer;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -542,26 +567,25 @@ void CBotStack::SetProgram(CBotProgram* p)
|
|||
{
|
||||
m_prog = p;
|
||||
m_func = IsFunction::YES;
|
||||
if (this == m_data->topStack) m_data->baseProg = p;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
CBotProgram* CBotStack::GetProgram(bool bFirst)
|
||||
{
|
||||
if ( ! bFirst ) return m_prog;
|
||||
CBotStack* p = this;
|
||||
while ( p->m_prev != nullptr ) p = p->m_prev;
|
||||
return p->m_prog;
|
||||
return m_data->baseProg;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void* CBotStack::GetUserPtr()
|
||||
{
|
||||
return m_pUser;
|
||||
return m_data->pUser;
|
||||
}
|
||||
|
||||
void CBotStack::SetUserPtr(void* user)
|
||||
{
|
||||
m_pUser = user;
|
||||
m_data->pUser = user;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -908,13 +932,18 @@ bool CBotVar::RestoreState(std::istream &istr, CBotVar* &pVar)
|
|||
|
||||
if (isClass && p == nullptr) // set id for each item in this instance
|
||||
{
|
||||
CBotVar* pVars = pNew->GetItemList();
|
||||
CBotVar* pv = pNew->GetClass()->GetVar();
|
||||
while (pVars != nullptr && pv != nullptr)
|
||||
CBotClass* pClass = pNew->GetClass();
|
||||
CBotVar* pVars = (static_cast<CBotVarClass*>(pNew))->m_pVar;
|
||||
while (pClass != nullptr && pVars != nullptr)
|
||||
{
|
||||
pVars->m_ident = pv->m_ident;
|
||||
pv = pv->GetNext();
|
||||
pVars = pVars->GetNext();
|
||||
CBotVar* pv = pClass->GetVar();
|
||||
while (pVars != nullptr && pv != nullptr)
|
||||
{
|
||||
pVars->m_ident = pv->m_ident;
|
||||
pVars = pVars->m_next;
|
||||
pv = pv->m_next;
|
||||
}
|
||||
pClass = pClass->GetParent();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -82,9 +82,6 @@ public:
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/** \name Error management
|
||||
*
|
||||
* BE CAREFUL - errors are stored in static variables!
|
||||
* \todo Refactor that
|
||||
*/
|
||||
//@{
|
||||
|
||||
|
@ -94,24 +91,21 @@ public:
|
|||
* \param[out] end Ending position in code of the error
|
||||
* \return Error number
|
||||
*/
|
||||
CBotError GetError(int& start, int& end) { start = m_start; end = m_end; return m_error; }
|
||||
CBotError GetError(int& start, int& end);
|
||||
|
||||
/**
|
||||
* \brief Get last error
|
||||
* \return Error number
|
||||
* \see GetError(int&, int&) for error position in code
|
||||
*/
|
||||
CBotError GetError() { return m_error; }
|
||||
CBotError GetError();
|
||||
|
||||
/**
|
||||
* \brief Check if there was an error
|
||||
* \return false if an error occurred
|
||||
* \see GetError()
|
||||
*/
|
||||
bool IsOk()
|
||||
{
|
||||
return m_error == CBotNoErr;
|
||||
}
|
||||
bool IsOk();
|
||||
|
||||
/**
|
||||
* \brief Set execution error unless it's already set unless you are trying to reset it
|
||||
|
@ -357,7 +351,7 @@ public:
|
|||
/**
|
||||
* \todo Document
|
||||
*
|
||||
* Copies the result value from static m_retvar (m_var at a moment of SetBreak(3)) to this stack result
|
||||
* Copies the result value from m_data->retvar (m_var at a moment of SetBreak(3)) to this stack result
|
||||
*/
|
||||
bool GetRetVar(bool bRet);
|
||||
|
||||
|
@ -446,11 +440,11 @@ public:
|
|||
*
|
||||
* \todo Full documentation of the timer
|
||||
*/
|
||||
static void SetTimer(int n);
|
||||
void SetTimer(int n);
|
||||
/**
|
||||
* \brief Get the current configured maximum number of "timer ticks" (parts of instructions) to execute
|
||||
*/
|
||||
static int GetTimer();
|
||||
int GetTimer();
|
||||
|
||||
/**
|
||||
* \brief Get current position in the program
|
||||
|
@ -476,10 +470,10 @@ private:
|
|||
|
||||
int m_state;
|
||||
int m_step;
|
||||
static CBotError m_error;
|
||||
static int m_start;
|
||||
static int m_end;
|
||||
static CBotVar* m_retvar; // result of a return
|
||||
|
||||
struct Data;
|
||||
|
||||
CBotStack::Data* m_data;
|
||||
|
||||
CBotVar* m_var; // result of the operations
|
||||
CBotVar* m_listVar; // variables declared at this level
|
||||
|
@ -489,11 +483,6 @@ private:
|
|||
//! CBotProgram instance the execution is in in this stack level
|
||||
CBotProgram* m_prog;
|
||||
|
||||
static int m_initimer;
|
||||
static int m_timer;
|
||||
static std::string m_labelBreak;
|
||||
static void* m_pUser;
|
||||
|
||||
//! The corresponding instruction
|
||||
CBotInstr* m_instr;
|
||||
//! If this stack level holds a function call
|
||||
|
|
|
@ -54,7 +54,6 @@ CBotVarClass::CBotVarClass(const CBotToken& name, const CBotTypResult& type) : C
|
|||
// official type for this object
|
||||
|
||||
m_pClass = nullptr;
|
||||
m_pParent = nullptr;
|
||||
m_binit = InitType::UNDEF;
|
||||
m_bStatic = false;
|
||||
m_mPrivate = ProtectionLevel::Public;
|
||||
|
@ -63,14 +62,9 @@ CBotVarClass::CBotVarClass(const CBotToken& name, const CBotTypResult& type) : C
|
|||
m_ItemIdent = type.Eq(CBotTypIntrinsic) ? 0 : CBotVar::NextUniqNum();
|
||||
|
||||
// add to the list
|
||||
m_instances.insert(this);
|
||||
if (m_ItemIdent != 0) m_instances.insert(this);
|
||||
|
||||
CBotClass* pClass = type.GetClass();
|
||||
if ( pClass != nullptr && pClass->GetParent() != nullptr )
|
||||
{
|
||||
// also creates an instance of the parent class
|
||||
m_pParent = new CBotVarClass(name, CBotTypResult(type.GetType(), pClass->GetParent()) ); //, nIdent);
|
||||
}
|
||||
|
||||
SetClass( pClass );
|
||||
|
||||
|
@ -82,11 +76,8 @@ CBotVarClass::~CBotVarClass( )
|
|||
if ( m_CptUse != 0 )
|
||||
assert(0);
|
||||
|
||||
if ( m_pParent ) delete m_pParent;
|
||||
m_pParent = nullptr;
|
||||
|
||||
// removes the class list
|
||||
m_instances.erase(this);
|
||||
if (m_ItemIdent != 0) m_instances.erase(this);
|
||||
|
||||
delete m_pVar;
|
||||
}
|
||||
|
@ -113,10 +104,6 @@ void CBotVarClass::Copy(CBotVar* pSrc, bool bName)
|
|||
m_binit = p->m_binit;
|
||||
//- m_bStatic = p->m_bStatic;
|
||||
m_pClass = p->m_pClass;
|
||||
if ( p->m_pParent )
|
||||
{
|
||||
assert(0); // "que faire du pParent";
|
||||
}
|
||||
|
||||
// m_next = nullptr;
|
||||
m_pUserPtr = p->m_pUserPtr;
|
||||
|
@ -162,9 +149,11 @@ void CBotVarClass::SetClass(CBotClass* pClass)//, int &nIdent)
|
|||
|
||||
if (pClass == nullptr) return;
|
||||
|
||||
CBotVar* pv = pClass->GetVar(); // first on a list
|
||||
while ( pv != nullptr )
|
||||
CBotVar* pv = nullptr;
|
||||
while (pClass != nullptr)
|
||||
{
|
||||
if ( pv == nullptr ) pv = pClass->GetVar();
|
||||
if ( pv == nullptr ) { pClass = pClass->GetParent(); continue; }
|
||||
// seeks the maximum dimensions of the table
|
||||
CBotInstr* p = pv->m_LimExpr; // the different formulas
|
||||
if ( p != nullptr )
|
||||
|
@ -214,6 +203,7 @@ void CBotVarClass::SetClass(CBotClass* pClass)//, int &nIdent)
|
|||
if ( m_pVar == nullptr) m_pVar = pn;
|
||||
else m_pVar->AddNext( pn );
|
||||
pv = pv->GetNext();
|
||||
if ( pv == nullptr ) pClass = pClass->GetParent();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -246,7 +236,6 @@ CBotVar* CBotVarClass::GetItem(const std::string& name)
|
|||
p = p->GetNext();
|
||||
}
|
||||
|
||||
if ( m_pParent != nullptr ) return m_pParent->GetItem(name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -261,7 +250,6 @@ CBotVar* CBotVarClass::GetItemRef(int nIdent)
|
|||
p = p->GetNext();
|
||||
}
|
||||
|
||||
if ( m_pParent != nullptr ) return m_pParent->GetItemRef(nIdent);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -311,32 +299,46 @@ std::string CBotVarClass::GetValString()
|
|||
{
|
||||
res = m_pClass->GetName() + std::string("( ");
|
||||
|
||||
CBotVarClass* my = this;
|
||||
while ( my != nullptr )
|
||||
CBotClass* pClass = m_pClass;
|
||||
long prevID = 0;
|
||||
{
|
||||
CBotVar* pv = my->m_pVar;
|
||||
while ( pv != nullptr )
|
||||
CBotVar* pv = m_pVar;
|
||||
if (pv != nullptr) while (true)
|
||||
{
|
||||
if (pv->GetUniqNum() < prevID)
|
||||
{
|
||||
pClass = pClass->GetParent();
|
||||
if (pClass == nullptr) break;
|
||||
res += " ) extends ";
|
||||
res += pClass->GetName();
|
||||
res += "( ";
|
||||
if (pClass->GetVar() == nullptr) continue;
|
||||
}
|
||||
|
||||
prevID = pv->GetUniqNum();
|
||||
|
||||
res += pv->GetName() + std::string("=");
|
||||
|
||||
if ( pv->IsStatic() )
|
||||
{
|
||||
CBotVar* pvv = my->m_pClass->GetItem(pv->GetName());
|
||||
res += pvv->GetValString();
|
||||
res += pClass->GetItemRef(prevID)->GetValString();
|
||||
}
|
||||
else
|
||||
{
|
||||
res += pv->GetValString();
|
||||
}
|
||||
pv = pv->GetNext();
|
||||
if ( pv != nullptr ) res += ", ";
|
||||
if ( pv == nullptr ) break;
|
||||
if ( pv->GetUniqNum() > prevID ) res += ", ";
|
||||
}
|
||||
my = my->m_pParent;
|
||||
if ( my != nullptr )
|
||||
|
||||
if (pClass != nullptr) while (true)
|
||||
{
|
||||
res += ") extends ";
|
||||
res += my->m_pClass->GetName();
|
||||
res += " (";
|
||||
pClass = pClass->GetParent();
|
||||
if (pClass == nullptr) break;
|
||||
res += " ) extends ";
|
||||
res += pClass->GetName();
|
||||
res += "( ";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -378,14 +380,7 @@ void CBotVarClass::DecrementUse()
|
|||
{
|
||||
m_CptUse++; // does not return to the destructor
|
||||
|
||||
// m_error is static in the stack
|
||||
// saves the value for return
|
||||
CBotError err;
|
||||
int start, end;
|
||||
CBotStack* pile = nullptr;
|
||||
err = pile->GetError(start,end); // stack == nullptr it does not bother!
|
||||
|
||||
pile = CBotStack::AllocateStack(); // clears the error
|
||||
CBotStack* pile = CBotStack::AllocateStack();
|
||||
CBotVar* ppVars[1];
|
||||
ppVars[0] = nullptr;
|
||||
|
||||
|
@ -399,8 +394,6 @@ void CBotVarClass::DecrementUse()
|
|||
|
||||
while ( pile->IsOk() && !m_pClass->ExecuteMethode(ident, pThis, ppVars, CBotTypResult(CBotTypVoid), pile, &token)) ; // waits for the end
|
||||
|
||||
pile->ResetError(err, start,end);
|
||||
|
||||
pile->Delete();
|
||||
delete pThis;
|
||||
m_CptUse--;
|
||||
|
|
|
@ -99,8 +99,6 @@ private:
|
|||
static std::set<CBotVarClass*> m_instances;
|
||||
//! Class definition
|
||||
CBotClass* m_pClass;
|
||||
//! Parent class instance
|
||||
CBotVarClass* m_pParent;
|
||||
//! Class members
|
||||
CBotVar* m_pVar;
|
||||
//! Reference counter
|
||||
|
|
|
@ -3411,7 +3411,6 @@ private:
|
|||
|
||||
void CScriptFunctions::Init()
|
||||
{
|
||||
CBotProgram::SetTimer(100);
|
||||
CBotProgram::Init();
|
||||
|
||||
for (int i = 0; i < OBJECT_MAX; i++)
|
||||
|
|
|
@ -812,6 +812,48 @@ TEST_F(CBotUT, ToString)
|
|||
"}\n"
|
||||
);
|
||||
|
||||
ExecuteTest(
|
||||
"extern void ClassToString_2()\n"
|
||||
"{\n"
|
||||
" string s = new TestClass;\n"
|
||||
" ASSERT(s == \"Pointer to TestClass( )\");\n"
|
||||
"}\n"
|
||||
"public class TestClass { /* no fields */ }\n"
|
||||
);
|
||||
|
||||
ExecuteTest(
|
||||
"extern void ClassInheritanceToString()\n"
|
||||
"{\n"
|
||||
" string s = new SubClass;\n"
|
||||
" ASSERT(s == \"Pointer to SubClass( c=7, d=8, e=9 ) extends MidClass( b=4, c=5, d=6 ) extends BaseClass( a=1, b=2, c=3 )\");\n"
|
||||
"}\n"
|
||||
"public class BaseClass { int a = 1, b = 2, c = 3; }\n"
|
||||
"public class MidClass extends BaseClass { int b = 4, c = 5, d = 6; }\n"
|
||||
"public class SubClass extends MidClass { int c = 7, d = 8, e = 9; }\n"
|
||||
);
|
||||
|
||||
ExecuteTest(
|
||||
"extern void ClassInheritanceToString_2()\n"
|
||||
"{\n"
|
||||
" string s = new SubClass;\n"
|
||||
" ASSERT(s == \"Pointer to SubClass( c=7, d=8, e=9 ) extends MidClass( ) extends BaseClass( a=1, b=2, c=3 )\");\n"
|
||||
"}\n"
|
||||
"public class BaseClass { int a = 1, b = 2, c = 3; }\n"
|
||||
"public class MidClass extends BaseClass { /* no fields */ }\n"
|
||||
"public class SubClass extends MidClass { int c = 7, d = 8, e = 9; }\n"
|
||||
);
|
||||
|
||||
ExecuteTest(
|
||||
"extern void ClassInheritanceToString_3()\n"
|
||||
"{\n"
|
||||
" string s = new SubClass;\n"
|
||||
" ASSERT(s == \"Pointer to SubClass( c=7, d=8, e=9 ) extends MidClass( ) extends BaseClass( )\");\n"
|
||||
"}\n"
|
||||
"public class BaseClass { /* no fields */ }\n"
|
||||
"public class MidClass extends BaseClass { /* no fields */ }\n"
|
||||
"public class SubClass extends MidClass { int c = 7, d = 8, e = 9; }\n"
|
||||
);
|
||||
|
||||
// TODO: IntrinsicClassToString ? (e.g. point)
|
||||
}
|
||||
|
||||
|
@ -3262,3 +3304,25 @@ TEST_F(CBotUT, ClassTestPrivateMethod)
|
|||
CBotErrPrivate
|
||||
);
|
||||
}
|
||||
|
||||
TEST_F(CBotUT, ClassTestSaveInheritedMembers)
|
||||
{
|
||||
auto publicProgram = ExecuteTest(
|
||||
"public class TestClass { int a = 123; }\n"
|
||||
"public class TestClass2 extends TestClass { int b = 456; }\n"
|
||||
);
|
||||
// Note: Use --CBotUT_TestSaveState command line arg.
|
||||
ExecuteTest(
|
||||
"extern void TestSaveInheritedMembers()\n"
|
||||
"{\n"
|
||||
" TestClass2 t();\n"
|
||||
" ASSERT(t.a == 123);\n"
|
||||
" ASSERT(t.b == 456);\n"
|
||||
" t.a = 789; t.b = 1011;\n"
|
||||
" ASSERT(t.a == 789);\n"
|
||||
" ASSERT(t.b == 1011);\n"
|
||||
" ASSERT(789 == t.a);\n"
|
||||
" ASSERT(1011 == t.b);\n"
|
||||
"}\n"
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue