diff --git a/src/CBot/CBotCStack.cpp b/src/CBot/CBotCStack.cpp index 5065ddfa..ba48ebcb 100644 --- a/src/CBot/CBotCStack.cpp +++ b/src/CBot/CBotCStack.cpp @@ -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 diff --git a/src/CBot/CBotCStack.h b/src/CBot/CBotCStack.h index 983dcf42..adcbee59 100644 --- a/src/CBot/CBotCStack.h +++ b/src/CBot/CBotCStack.h @@ -22,6 +22,9 @@ #include "CBot/CBotVar/CBotVar.h" #include "CBot/CBotProgram.h" +#include +#include + 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 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 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> m_listVar; }; } // namespace CBot diff --git a/src/CBot/CBotClass.cpp b/src/CBot/CBotClass.cpp index ccf47104..a7993a9a 100644 --- a/src/CBot/CBotClass.cpp +++ b/src/CBot/CBotClass.cpp @@ -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::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(); diff --git a/src/CBot/CBotDefParam.cpp b/src/CBot/CBotDefParam.cpp index de3fd503..d25f9bda 100644 --- a/src/CBot/CBotDefParam.cpp +++ b/src/CBot/CBotDefParam.cpp @@ -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; diff --git a/src/CBot/CBotExternalCall.cpp b/src/CBot/CBotExternalCall.cpp index 8862212b..5b1b4c73 100644 --- a/src/CBot/CBotExternalCall.cpp +++ b/src/CBot/CBotExternalCall.cpp @@ -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 diff --git a/src/CBot/CBotInstr/CBotDefClass.cpp b/src/CBot/CBotInstr/CBotDefClass.cpp index c7711703..f50196ed 100644 --- a/src/CBot/CBotInstr/CBotDefClass.cpp +++ b/src/CBot/CBotInstr/CBotDefClass.cpp @@ -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? diff --git a/src/CBot/CBotInstr/CBotFunction.cpp b/src/CBot/CBotInstr/CBotFunction.cpp index 478b9196..e4a62e95 100644 --- a/src/CBot/CBotInstr/CBotFunction.cpp +++ b/src/CBot/CBotInstr/CBotFunction.cpp @@ -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 ); diff --git a/src/CBot/CBotInstr/CBotInstrCall.cpp b/src/CBot/CBotInstr/CBotInstrCall.cpp index 60689cb1..2274f3ac 100644 --- a/src/CBot/CBotInstr/CBotInstrCall.cpp +++ b/src/CBot/CBotInstr/CBotInstrCall.cpp @@ -78,12 +78,12 @@ CBotInstr* CBotInstrCall::Compile(CBotToken* &p, CBotCStack* pStack) { // if (pVar2!=nullptr) pp = pVar2->RetToken(); pStack->SetError( static_cast(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? diff --git a/src/CBot/CBotInstr/CBotInstrMethode.cpp b/src/CBot/CBotInstr/CBotInstrMethode.cpp index 12c50466..6b7045e3 100644 --- a/src/CBot/CBotInstr/CBotInstrMethode.cpp +++ b/src/CBot/CBotInstr/CBotInstrMethode.cpp @@ -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; } diff --git a/src/CBot/CBotInstr/CBotInstrUtils.cpp b/src/CBot/CBotInstr/CBotInstrUtils.cpp index 0b56267c..c4638d60 100644 --- a/src/CBot/CBotInstr/CBotInstrUtils.cpp +++ b/src/CBot/CBotInstr/CBotInstrUtils.cpp @@ -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; } } diff --git a/src/CBot/CBotInstr/CBotNew.cpp b/src/CBot/CBotInstr/CBotNew.cpp index 5f7539b1..dd8d04ac 100644 --- a/src/CBot/CBotInstr/CBotNew.cpp +++ b/src/CBot/CBotInstr/CBotNew.cpp @@ -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? diff --git a/src/CBot/CBotInstr/CBotSwitch.cpp b/src/CBot/CBotInstr/CBotSwitch.cpp index 9436407b..c75e9aa1 100644 --- a/src/CBot/CBotInstr/CBotSwitch.cpp +++ b/src/CBot/CBotInstr/CBotSwitch.cpp @@ -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::Compile(p, pStk2, inst->m_labels)); diff --git a/src/CBot/CBotInstr/CBotTwoOpExpr.cpp b/src/CBot/CBotInstr/CBotTwoOpExpr.cpp index a1339724..f57633d5 100644 --- a/src/CBot/CBotInstr/CBotTwoOpExpr.cpp +++ b/src/CBot/CBotInstr/CBotTwoOpExpr.cpp @@ -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 } diff --git a/src/CBot/CBotProgram.cpp b/src/CBot/CBotProgram.cpp index 428f1086..4a09eef2 100644 --- a/src/CBot/CBotProgram.cpp +++ b/src/CBot/CBotProgram.cpp @@ -34,7 +34,7 @@ namespace CBot { -CBotExternalCallList* CBotProgram::m_externalCalls = new CBotExternalCallList(); +std::unique_ptr 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& CBotProgram::GetExternalCalls() { return m_externalCalls; } diff --git a/src/CBot/CBotProgram.h b/src/CBot/CBotProgram.h index 8d7576f2..41ef6b8b 100644 --- a/src/CBot/CBotProgram.h +++ b/src/CBot/CBotProgram.h @@ -19,11 +19,12 @@ #pragma once -#include "CBot/CBotTypResult.h" #include "CBot/CBotEnums.h" -#include #include +#include +#include +#include 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& GetExternalCalls(); private: //! All external calls - static CBotExternalCallList* m_externalCalls; + static std::unique_ptr m_externalCalls; //! All user-defined functions std::list m_functions{}; //! The entry point function diff --git a/src/CBot/CBotStack.cpp b/src/CBot/CBotStack.cpp index d6377c7b..7de0670b 100644 --- a/src/CBot/CBotStack.cpp +++ b/src/CBot/CBotStack.cpp @@ -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 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(-val); // reacts as an Exception - m_labelBreak = name; + m_data->error = static_cast(-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(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(); } } diff --git a/src/CBot/CBotStack.h b/src/CBot/CBotStack.h index 20e8118d..64a81124 100644 --- a/src/CBot/CBotStack.h +++ b/src/CBot/CBotStack.h @@ -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 diff --git a/src/CBot/CBotVar/CBotVarClass.cpp b/src/CBot/CBotVar/CBotVarClass.cpp index 98d95f44..3ee19874 100644 --- a/src/CBot/CBotVar/CBotVarClass.cpp +++ b/src/CBot/CBotVar/CBotVarClass.cpp @@ -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--; diff --git a/src/CBot/CBotVar/CBotVarClass.h b/src/CBot/CBotVar/CBotVarClass.h index 6e98f62e..ac462d99 100644 --- a/src/CBot/CBotVar/CBotVarClass.h +++ b/src/CBot/CBotVar/CBotVarClass.h @@ -99,8 +99,6 @@ private: static std::set m_instances; //! Class definition CBotClass* m_pClass; - //! Parent class instance - CBotVarClass* m_pParent; //! Class members CBotVar* m_pVar; //! Reference counter diff --git a/src/script/scriptfunc.cpp b/src/script/scriptfunc.cpp index ad1a3839..f35c7a2f 100644 --- a/src/script/scriptfunc.cpp +++ b/src/script/scriptfunc.cpp @@ -3411,7 +3411,6 @@ private: void CScriptFunctions::Init() { - CBotProgram::SetTimer(100); CBotProgram::Init(); for (int i = 0; i < OBJECT_MAX; i++) diff --git a/test/unit/CBot/CBot_test.cpp b/test/unit/CBot/CBot_test.cpp index 66ebf381..1e4aac06 100644 --- a/test/unit/CBot/CBot_test.cpp +++ b/test/unit/CBot/CBot_test.cpp @@ -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" + ); +}