/* * This file is part of the Colobot: Gold Edition source code * Copyright (C) 2001-2016, Daniel Roux, EPSITEC SA & TerranovaTeam * http://epsitec.ch; http://colobot.info; http://github.com/colobot * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://gnu.org/licenses */ #include "CBot/CBotInstr/CBotFunction.h" #include "CBot/CBotInstr/CBotInstrUtils.h" #include "CBot/CBotInstr/CBotBlock.h" #include "CBot/CBotInstr/CBotTwoOpExpr.h" #include "CBot/CBotInstr/CBotExpression.h" #include "CBot/CBotInstr/CBotEmpty.h" #include "CBot/CBotInstr/CBotListArray.h" #include "CBot/CBotStack.h" #include "CBot/CBotCStack.h" #include "CBot/CBotClass.h" #include "CBot/CBotDefParam.h" #include "CBot/CBotUtils.h" #include "CBot/CBotVar/CBotVar.h" #include #include namespace CBot { //////////////////////////////////////////////////////////////////////////////// CBotFunction::CBotFunction() { m_param = nullptr; // empty parameter list m_block = nullptr; // the instruction block m_next = nullptr; // functions can be chained m_bPublic = false; // function not public m_bExtern = false; // function not extern m_pProg = nullptr; // m_nThisIdent = 0; m_nFuncIdent = 0; m_bSynchro = false; } //////////////////////////////////////////////////////////////////////////////// std::set CBotFunction::m_publicFunctions{}; //////////////////////////////////////////////////////////////////////////////// CBotFunction::~CBotFunction() { delete m_param; // empty parameter list delete m_block; // the instruction block delete m_next; // remove public list if there is if (m_bPublic) { m_publicFunctions.erase(this); } } //////////////////////////////////////////////////////////////////////////////// bool CBotFunction::IsPublic() { return m_bPublic; } //////////////////////////////////////////////////////////////////////////////// bool CBotFunction::IsExtern() { return m_bExtern; } //////////////////////////////////////////////////////////////////////////////// bool CBotFunction::GetPosition(int& start, int& stop, CBotGet modestart, CBotGet modestop) { start = m_extern.GetStart(); stop = m_closeblk.GetEnd(); if (modestart == GetPosExtern) { start = m_extern.GetStart(); } if (modestop == GetPosExtern) { stop = m_extern.GetEnd(); } if (modestart == GetPosNom) { start = m_token.GetStart(); } if (modestop == GetPosNom) { stop = m_token.GetEnd(); } if (modestart == GetPosParam) { start = m_openpar.GetStart(); } if (modestop == GetPosParam) { stop = m_closepar.GetEnd(); } if (modestart == GetPosBloc) { start = m_openblk.GetStart(); } if (modestop == GetPosBloc) { stop = m_closeblk.GetEnd(); } return true; } //////////////////////////////////////////////////////////////////////////////// CBotFunction* CBotFunction::Compile(CBotToken* &p, CBotCStack* pStack, CBotFunction* finput, bool bLocal) { CBotToken* pp; CBotFunction* func = finput; if ( func == nullptr ) func = new CBotFunction(); CBotCStack* pStk = pStack->TokenStack(p, bLocal); // func->m_nFuncIdent = CBotVar::NextUniqNum(); while (true) { if ( IsOfType(p, ID_PUBLIC) ) { func->m_bPublic = true; continue; } pp = p; if ( IsOfType(p, ID_EXTERN) ) { func->m_extern = *pp; // for the position of the word "extern" func->m_bExtern = true; // func->m_bPublic = true; // therefore also public! continue; } break; } func->m_retToken = *p; // CBotClass* pClass; func->m_retTyp = TypeParam(p, pStk); // type of the result if (func->m_retTyp.GetType() >= 0) { CBotToken* pp = p; func->m_token = *p; if ( IsOfType(p, ID_NOT) ) { CBotToken d(std::string("~") + p->GetString()); func->m_token = d; } // un nom de fonction est-il là ? if (IsOfType(p, TokenTypVar)) { if ( IsOfType( p, ID_DBLDOTS ) ) // method for a class { func->m_MasterClass = pp->GetString(); func->m_classToken = *pp; CBotClass* pClass = CBotClass::Find(pp); if ( pClass == nullptr ) goto bad; // pp = p; func->m_token = *p; if (!IsOfType(p, TokenTypVar)) goto bad; } func->m_openpar = *p; func->m_param = CBotDefParam::Compile(p, pStk ); func->m_closepar = *(p->GetPrev()); if (pStk->IsOk()) { pStk->SetRetType(func->m_retTyp); // for knowledge what type returns if (!func->m_MasterClass.empty()) { // return "this" known CBotVar* pThis = CBotVar::Create("this", CBotTypResult( CBotTypClass, func->m_MasterClass )); pThis->SetInit(CBotVar::InitType::IS_POINTER); // pThis->SetUniqNum(func->m_nThisIdent = -2); //CBotVar::NextUniqNum() will not pThis->SetUniqNum(-2); pStk->AddVar(pThis); // initialize variables acording to This // only saves the pointer to the first, // the rest is chained CBotVar* pv = pThis->GetItemList(); // int num = 1; while (pv != nullptr) { CBotVar* pcopy = CBotVar::Create(pv); // pcopy->SetInit(2); pcopy->Copy(pv); pcopy->SetPrivate(pv->GetPrivate()); // pcopy->SetUniqNum(pv->GetUniqNum()); //num++); pStk->AddVar(pcopy); pv = pv->GetNext(); } } // and compiles the following instruction block func->m_openblk = *p; func->m_block = CBotBlock::Compile(p, pStk, false); func->m_closeblk = (p != nullptr && p->GetPrev() != nullptr) ? *(p->GetPrev()) : CBotToken(); if ( pStk->IsOk() ) { return pStack->ReturnFunc(func, pStk); } } } bad: pStk->SetError(CBotErrNoFunc, p); } pStk->SetError(CBotErrNoType, p); if ( finput == nullptr ) delete func; return pStack->ReturnFunc(nullptr, pStk); } //////////////////////////////////////////////////////////////////////////////// CBotFunction* CBotFunction::Compile1(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass) { CBotFunction* func = new CBotFunction(); func->m_nFuncIdent = CBotVar::NextUniqNum(); CBotCStack* pStk = pStack->TokenStack(p, true); while (true) { if ( IsOfType(p, ID_PUBLIC) ) { // func->m_bPublic = true; // will be done in two passes continue; } if ( IsOfType(p, ID_EXTERN) ) { func->m_bExtern = true; continue; } break; } func->m_retToken = *p; func->m_retTyp = TypeParam(p, pStack); // type of the result if (func->m_retTyp.GetType() >= 0) { CBotToken* pp = p; func->m_token = *p; if ( IsOfType(p, ID_NOT) ) { CBotToken d(std::string("~") + p->GetString()); func->m_token = d; } // un nom de fonction est-il là ? if (IsOfType(p, TokenTypVar)) { if ( IsOfType( p, ID_DBLDOTS ) ) // method for a class { func->m_MasterClass = pp->GetString(); CBotClass* pClass = CBotClass::Find(pp); if ( pClass == nullptr ) { pStk->SetError(CBotErrNotClass, pp); goto bad; } pp = p; func->m_token = *p; if (!IsOfType(p, TokenTypVar)) goto bad; } func->m_param = CBotDefParam::Compile(p, pStk ); if (pStk->IsOk()) { // looks if the function exists elsewhere if (( pClass != nullptr || !pStack->CheckCall(pp, func->m_param)) && ( pClass == nullptr || !pClass->CheckCall(pStack->GetProgram(), func->m_param, pp)) ) { if (IsOfType(p, ID_OPBLK)) { int level = 1; // and skips the following instruction block do { int type = p->GetType(); p = p->GetNext(); if (type == ID_OPBLK) level++; if (type == ID_CLBLK) level--; } while (level > 0 && p != nullptr); return pStack->ReturnFunc(func, pStk); } pStk->SetError(CBotErrOpenBlock, p); } } pStk->SetError(CBotErrRedefFunc, pp); } bad: pStk->SetError(CBotErrNoFunc, p); } pStk->SetError(CBotErrNoType, p); delete func; return pStack->ReturnFunc(nullptr, pStk); } //////////////////////////////////////////////////////////////////////////////// bool CBotFunction::Execute(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance) { CBotStack* pile = pj->AddStack(this, CBotStack::BlockVisibilityType::FUNCTION); // one end of stack local to this function // if ( pile == EOX ) return true; pile->SetProgram(m_pProg); // bases for routines if ( pile->GetState() == 0 ) { if ( !m_param->Execute(ppVars, pile) ) return false; // define parameters pile->IncState(); } if ( pile->GetState() == 1 && !m_MasterClass.empty() ) { // makes "this" known CBotVar* pThis = nullptr; if ( pInstance == nullptr ) { pThis = CBotVar::Create("this", CBotTypResult( CBotTypClass, m_MasterClass )); } else { if (m_MasterClass != pInstance->GetClass()->GetName()) { pile->SetError(CBotErrBadType2, &m_classToken); return false; } pThis = CBotVar::Create("this", CBotTypResult( CBotTypPointer, m_MasterClass )); pThis->SetPointer(pInstance); } assert(pThis != nullptr); pThis->SetInit(CBotVar::InitType::IS_POINTER); // pThis->SetUniqNum(m_nThisIdent); pThis->SetUniqNum(-2); pile->AddVar(pThis); pile->IncState(); } if ( pile->IfStep() ) return false; if ( !m_block->Execute(pile) ) { if ( pile->GetError() < 0 ) pile->SetError( CBotNoErr ); else return false; } return pj->Return(pile); } //////////////////////////////////////////////////////////////////////////////// void CBotFunction::RestoreState(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance) { CBotStack* pile = pj->RestoreStack(this); // one end of stack local to this function if ( pile == nullptr ) return; CBotStack* pile2 = pile; pile->SetProgram(m_pProg); // bases for routines if ( pile->GetBlock() != CBotStack::BlockVisibilityType::FUNCTION) { CBotStack* pile2 = pile->RestoreStack(nullptr); // one end of stack local to this function if ( pile2 == nullptr ) return; pile->SetState(pile->GetState() + pile2->GetState()); pile2->Delete(); } m_param->RestoreState(pile2, true); // parameters if ( !m_MasterClass.empty() ) { CBotVar* pThis = pile->FindVar("this"); pThis->SetInit(CBotVar::InitType::IS_POINTER); pThis->SetUniqNum(-2); } m_block->RestoreState(pile2, true); } //////////////////////////////////////////////////////////////////////////////// void CBotFunction::AddNext(CBotFunction* p) { CBotFunction* pp = this; while (pp->m_next != nullptr) pp = pp->m_next; pp->m_next = p; } //////////////////////////////////////////////////////////////////////////////// CBotTypResult CBotFunction::CompileCall(CBotFunction* localFunctionList, const std::string &name, CBotVar** ppVars, long &nIdent) { CBotTypResult type; if (!FindLocalOrPublic(localFunctionList, nIdent, name, ppVars, type)) { // Reset the identifier to "not found" value nIdent = 0; } return type; } //////////////////////////////////////////////////////////////////////////////// CBotFunction* CBotFunction::FindLocalOrPublic(CBotFunction* localFunctionList, long &nIdent, const std::string &name, CBotVar** ppVars, CBotTypResult &TypeOrError, bool bPublic) { TypeOrError.SetType(CBotErrUndefCall); // no routine of the name CBotFunction* pt; if ( nIdent ) { if ( localFunctionList != nullptr ) for ( pt = localFunctionList ; pt != nullptr ; pt = pt->m_next ) { if ( pt->m_nFuncIdent == nIdent ) { TypeOrError = pt->m_retTyp; return pt; } } // search the list of public functions for (CBotFunction* pt : m_publicFunctions) { if (pt->m_nFuncIdent == nIdent) { TypeOrError = pt->m_retTyp; return pt; } } } if ( name.empty() ) return nullptr; std::map funcMap; if ( localFunctionList != nullptr ) { for ( pt = localFunctionList ; pt != nullptr ; pt = pt->m_next ) { if ( pt->m_token.GetString() == name ) { int i = 0; int alpha = 0; // signature of parameters // parameters are compatible? CBotDefParam* pv = pt->m_param; // expected list of parameters CBotVar* pw = ppVars[i++]; // provided list parameter while ( pv != nullptr && pw != nullptr) { CBotTypResult paramType = pv->GetTypResult(); CBotTypResult argType = pw->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC); if (!TypesCompatibles(paramType, argType)) { if ( funcMap.empty() ) TypeOrError.SetType(CBotErrBadParam); break; } if (paramType.Eq(CBotTypPointer) && !argType.Eq(CBotTypNullPointer)) { CBotClass* c1 = paramType.GetClass(); CBotClass* c2 = argType.GetClass(); while (c2 != c1 && c2 != nullptr) // implicit cast { alpha += 10; c2 = c2->GetParent(); } } else { int d = pv->GetType() - pw->GetType(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC); alpha += d>0 ? d : -10*d; // quality loss, 10 times more expensive! } pv = pv->GetNext(); pw = ppVars[i++]; } if ( pw != nullptr ) { if ( !funcMap.empty() ) continue; if ( TypeOrError.Eq(CBotErrLowParam) ) TypeOrError.SetType(CBotErrNbParam); if ( TypeOrError.Eq(CBotErrUndefCall)) TypeOrError.SetType(CBotErrOverParam); continue; // too many parameters } if ( pv != nullptr ) { if ( !funcMap.empty() ) continue; if ( TypeOrError.Eq(CBotErrOverParam) ) TypeOrError.SetType(CBotErrNbParam); if ( TypeOrError.Eq(CBotErrUndefCall) ) TypeOrError.SetType(CBotErrLowParam); continue; // not enough parameters } funcMap.insert( std::pair(pt, alpha) ); } } } if ( bPublic ) { for (CBotFunction* pt : m_publicFunctions) { if ( pt->m_token.GetString() == name ) { int i = 0; int alpha = 0; // signature of parameters // parameters sont-ils compatibles ? CBotDefParam* pv = pt->m_param; // list of expected parameters CBotVar* pw = ppVars[i++]; // list of provided parameters while ( pv != nullptr && pw != nullptr) { CBotTypResult paramType = pv->GetTypResult(); CBotTypResult argType = pw->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC); if (!TypesCompatibles(paramType, argType)) { if ( funcMap.empty() ) TypeOrError.SetType(CBotErrBadParam); break; } if (paramType.Eq(CBotTypPointer) && !argType.Eq(CBotTypNullPointer)) { CBotClass* c1 = paramType.GetClass(); CBotClass* c2 = argType.GetClass(); while (c2 != c1 && c2 != nullptr) // implicit cast { alpha += 10; c2 = c2->GetParent(); } } else { int d = pv->GetType() - pw->GetType(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC); alpha += d>0 ? d : -10*d; // quality loss, 10 times more expensive! } pv = pv->GetNext(); pw = ppVars[i++]; } if ( pw != nullptr ) { if ( !funcMap.empty() ) continue; // previous useable function if ( TypeOrError.Eq(CBotErrLowParam) ) TypeOrError.SetType(CBotErrNbParam); if ( TypeOrError.Eq(CBotErrUndefCall)) TypeOrError.SetType(CBotErrOverParam); continue; // to many parameters } if ( pv != nullptr ) { if ( !funcMap.empty() ) continue; // previous useable function if ( TypeOrError.Eq(CBotErrOverParam) ) TypeOrError.SetType(CBotErrNbParam); if ( TypeOrError.Eq(CBotErrUndefCall) ) TypeOrError.SetType(CBotErrLowParam); continue; // not enough parameters } funcMap.insert( std::pair(pt, alpha) ); } } } if ( !funcMap.empty() ) { auto it = funcMap.begin(); CBotFunction* pFunc = it->first; // the best function found signed int delta = it->second; // seeks the lowest signature for (++it ; it != funcMap.end() ; it++) { if (it->second < delta) // a better signature? { TypeOrError.SetType(CBotNoErr); pFunc = it->first; delta = it->second; continue; } if (it->second == delta) TypeOrError.SetType(CBotErrAmbiguousCall); } if (TypeOrError.Eq(CBotErrAmbiguousCall)) return nullptr; nIdent = pFunc->m_nFuncIdent; TypeOrError = pFunc->m_retTyp; return pFunc; } return nullptr; } //////////////////////////////////////////////////////////////////////////////// int CBotFunction::DoCall(CBotProgram* program, CBotFunction* localFunctionList, long &nIdent, const std::string &name, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken) { CBotTypResult type; CBotFunction* pt = nullptr; pt = FindLocalOrPublic(localFunctionList, nIdent, name, ppVars, type); if ( pt != nullptr ) { CBotStack* pStk1 = pStack->AddStack(pt, CBotStack::BlockVisibilityType::FUNCTION); // to put "this" // if ( pStk1 == EOX ) return true; pStk1->SetProgram(pt->m_pProg); // it may have changed module if ( pStk1->IfStep() ) return false; CBotStack* pStk3 = pStk1->AddStack(nullptr, CBotStack::BlockVisibilityType::BLOCK); // parameters // preparing parameters on the stack if ( pStk1->GetState() == 0 ) { if ( !pt->m_MasterClass.empty() ) { CBotVar* pInstance = program->m_thisVar; // make "this" known CBotVar* pThis ; if ( pInstance == nullptr ) { pThis = CBotVar::Create("this", CBotTypResult( CBotTypClass, pt->m_MasterClass )); } else { if (pt->m_MasterClass != pInstance->GetClass()->GetName()) { pStack->SetError(CBotErrBadType2, &pt->m_classToken); return false; } pThis = CBotVar::Create("this", CBotTypResult( CBotTypPointer, pt->m_MasterClass )); pThis->SetPointer(pInstance); } assert(pThis != nullptr); pThis->SetInit(CBotVar::InitType::IS_POINTER); pThis->SetUniqNum(-2); pStk1->AddVar(pThis); } // initializes the variables as parameters pt->m_param->Execute(ppVars, pStk3); // cannot be interrupted pStk1->IncState(); } // finally execution of the found function if ( !pStk3->GetRetVar( // puts the result on the stack pt->m_block->Execute(pStk3) )) // GetRetVar said if it is interrupted { if ( !pStk3->IsOk() && pt->m_pProg != program ) { pStk3->SetPosError(pToken); // indicates the error on the procedure call } return false; // interrupt ! } return pStack->Return( pStk3 ); } return -1; } //////////////////////////////////////////////////////////////////////////////// void CBotFunction::RestoreCall(CBotFunction* localFunctionList, long &nIdent, const std::string &name, CBotVar** ppVars, CBotStack* pStack) { CBotTypResult type; CBotFunction* pt = nullptr; CBotStack* pStk1; CBotStack* pStk3; // search function to return the ok identifier pt = FindLocalOrPublic(localFunctionList, nIdent, name, ppVars, type); if ( pt != nullptr ) { pStk1 = pStack->RestoreStack(pt); if ( pStk1 == nullptr ) return; pStk1->SetProgram(pt->m_pProg); // it may have changed module if ( pStk1->GetBlock() != CBotStack::BlockVisibilityType::FUNCTION) { CBotStack* pStk2 = pStk1->RestoreStack(nullptr); // used more if ( pStk2 == nullptr ) return; pStk3 = pStk2->RestoreStack(nullptr); if ( pStk3 == nullptr ) return; } else { pStk3 = pStk1->RestoreStack(nullptr); if ( pStk3 == nullptr ) return; } // preparing parameters on the stack { if ( !pt->m_MasterClass.empty() ) { // CBotVar* pInstance = m_pProg->m_thisVar; // make "this" known CBotVar* pThis = pStk1->FindVar("this"); pThis->SetInit(CBotVar::InitType::IS_POINTER); pThis->SetUniqNum(-2); } } if ( pStk1->GetState() == 0 ) { pt->m_param->RestoreState(pStk3, true); return; } // initializes the variables as parameters pt->m_param->RestoreState(pStk3, false); pt->m_block->RestoreState(pStk3, true); } } //////////////////////////////////////////////////////////////////////////////// int CBotFunction::DoCall(CBotFunction* localFunctionList, long &nIdent, const std::string &name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken, CBotClass* pClass) { CBotTypResult type; CBotProgram* pProgCurrent = pStack->GetProgram(); CBotFunction* pt = FindLocalOrPublic(localFunctionList, nIdent, name, ppVars, type, false); if ( pt != nullptr ) { // DEBUG( "CBotFunction::DoCall" + pt->GetName(), 0, pStack); CBotStack* pStk = pStack->AddStack(pt, CBotStack::BlockVisibilityType::FUNCTION); // if ( pStk == EOX ) return true; pStk->SetProgram(pt->m_pProg); // it may have changed module CBotStack* pStk3 = pStk->AddStack(nullptr, CBotStack::BlockVisibilityType::BLOCK); // to set parameters passed // preparing parameters on the stack if ( pStk->GetState() == 0 ) { // sets the variable "this" on the stack CBotVar* pthis = CBotVar::Create("this", CBotTypNullPointer); pthis->Copy(pThis, false); pthis->SetUniqNum(-2); // special value pStk->AddVar(pthis); CBotClass* pClass = pThis->GetClass()->GetParent(); if ( pClass ) { // sets the variable "super" on the stack CBotVar* psuper = CBotVar::Create("super", CBotTypNullPointer); psuper->Copy(pThis, false); // in fact identical to "this" psuper->SetUniqNum(-3); // special value pStk->AddVar(psuper); } // initializes the variables as parameters pt->m_param->Execute(ppVars, pStk3); // cannot be interrupted pStk->IncState(); } if ( pStk->GetState() == 1 ) { if ( pt->m_bSynchro ) { CBotProgram* pProgBase = pStk->GetProgram(true); if ( !pClass->Lock(pProgBase) ) return false; // try to lock, interrupt if failed } pStk->IncState(); } // finally calls the found function if ( !pStk3->GetRetVar( // puts the result on the stack pt->m_block->Execute(pStk3) )) // GetRetVar said if it is interrupted { if ( !pStk3->IsOk() ) { if ( pt->m_bSynchro ) { pClass->Unlock(); // release function } if ( pt->m_pProg != pProgCurrent ) { pStk3->SetPosError(pToken); // indicates the error on the procedure call } } return false; // interrupt ! } if ( pt->m_bSynchro ) { pClass->Unlock(); // release function } return pStack->Return( pStk3 ); } return -1; } //////////////////////////////////////////////////////////////////////////////// bool CBotFunction::RestoreCall(CBotFunction* localFunctionList, long &nIdent, const std::string &name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotClass* pClass) { CBotTypResult type; CBotFunction* pt = FindLocalOrPublic(localFunctionList, nIdent, name, ppVars, type); if ( pt != nullptr ) { CBotStack* pStk = pStack->RestoreStack(pt); if ( pStk == nullptr ) return true; pStk->SetProgram(pt->m_pProg); // it may have changed module CBotVar* pthis = pStk->FindVar("this"); pthis->SetUniqNum(-2); if (pClass->GetParent() != nullptr) { CBotVar* psuper = pStk->FindVar("super"); if (psuper != nullptr) psuper->SetUniqNum(-3); } CBotStack* pStk3 = pStk->RestoreStack(nullptr); // to set parameters passed if ( pStk3 == nullptr ) return true; pt->m_param->RestoreState(pStk3, true); // parameters if ( pStk->GetState() > 1 && // latching is effective? pt->m_bSynchro ) { CBotProgram* pProgBase = pStk->GetProgram(true); pClass->Lock(pProgBase); // locks the class } // finally calls the found function pt->m_block->RestoreState(pStk3, true); // interrupt ! return true; } return false; } //////////////////////////////////////////////////////////////////////////////// bool CBotFunction::CheckParam(CBotDefParam* pParam) { CBotDefParam* pp = m_param; while ( pp != nullptr && pParam != nullptr ) { CBotTypResult type1 = pp->GetTypResult(); CBotTypResult type2 = pParam->GetTypResult(); if ( !type1.Compare(type2) ) return false; pp = pp->GetNext(); pParam = pParam->GetNext(); } return ( pp == nullptr && pParam == nullptr ); } //////////////////////////////////////////////////////////////////////////////// std::string CBotFunction::GetName() { return m_token.GetString(); } //////////////////////////////////////////////////////////////////////////////// std::string CBotFunction::GetParams() { if (m_param == nullptr ) return std::string("()"); std::string params = "( "; CBotDefParam* p = m_param; // list of parameters while (p != nullptr) { params += p->GetParamString(); p = p->GetNext(); if ( p != nullptr ) params += ", "; } params += " )"; return params; } //////////////////////////////////////////////////////////////////////////////// CBotFunction* CBotFunction::Next() { return m_next; } //////////////////////////////////////////////////////////////////////////////// void CBotFunction::AddPublic(CBotFunction* func) { m_publicFunctions.insert(func); } std::string CBotFunction::GetDebugData() { std::stringstream ss; if (IsPublic()) ss << "public "; if (IsExtern()) ss << "extern "; ss << GetName() << GetParams(); //ss << "FuncID = " << m_nFuncIdent; return ss.str(); } std::map CBotFunction::GetDebugLinks() { auto links = CBotInstr::GetDebugLinks(); links["m_block"] = m_block; return links; } } // namespace CBot