colobot/src/CBot/CBotInstr/CBotInstrCall.cpp

233 lines
6.7 KiB
C++
Raw Normal View History

/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2020, 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
*/
2015-12-31 13:44:19 +00:00
#include "CBot/CBotInstr/CBotInstrCall.h"
#include "CBot/CBotInstr/CBotExprRetVar.h"
#include "CBot/CBotInstr/CBotInstrUtils.h"
#include "CBot/CBotStack.h"
2015-12-31 13:44:19 +00:00
#include "CBot/CBotCStack.h"
#include "CBot/CBotVar/CBotVar.h"
2015-12-31 13:44:19 +00:00
#include <sstream>
2015-12-26 13:19:24 +00:00
namespace CBot
{
////////////////////////////////////////////////////////////////////////////////
CBotInstrCall::CBotInstrCall()
{
m_parameters = nullptr;
2017-01-16 18:00:01 +00:00
m_exprRetVar = nullptr;
m_nFuncIdent = 0;
}
////////////////////////////////////////////////////////////////////////////////
CBotInstrCall::~CBotInstrCall()
{
delete m_parameters;
2017-01-16 18:00:01 +00:00
delete m_exprRetVar;
}
////////////////////////////////////////////////////////////////////////////////
CBotInstr* CBotInstrCall::Compile(CBotToken* &p, CBotCStack* pStack)
{
CBotToken* pp = p;
p = p->GetNext();
if (p->GetType() == ID_OPENPAR)
{
CBotVar* ppVars[1000];
CBotInstrCall* inst = new CBotInstrCall();
inst->SetToken(pp);
// compile la list of parameters
inst->m_parameters = CompileParams(p, pStack, ppVars);
if ( !pStack->IsOk() )
{
delete inst;
return nullptr;
}
// the routine is known?
// CBotClass* pClass = nullptr;
inst->m_typRes = pStack->CompileCall(pp, ppVars, inst->m_nFuncIdent);
if ( inst->m_typRes.GetType() >= 20 )
{
// if (pVar2!=nullptr) pp = pVar2->RetToken();
2015-12-20 18:16:01 +00:00
pStack->SetError( static_cast<CBotError>(inst->m_typRes.GetType()), pp );
pStack->DeleteNext();
delete inst;
return nullptr;
}
pStack->DeleteNext();
if ( inst->m_typRes.GetType() > 0 )
{
CBotVar* pRes = CBotVar::Create("", inst->m_typRes);
pStack->SetVar(pRes); // for knowing the type of the result
}
else pStack->SetVar(nullptr); // routine returns void
if (nullptr != (inst->m_exprRetVar = CBotExprRetVar::Compile(p, pStack)))
{
inst->m_exprRetVar->SetToken(&inst->m_token);
pStack->DeleteNext();
}
if ( !pStack->IsOk() )
{
delete inst;
return nullptr;
}
return inst;
}
p = pp;
pStack->DeleteNext();
return nullptr;
}
////////////////////////////////////////////////////////////////////////////////
bool CBotInstrCall::Execute(CBotStack* &pj)
{
CBotVar* ppVars[1000];
CBotStack* pile = pj->AddStack(this);
if ( pile->StackOver() ) return pj->Return( pile );
CBotStack* pile3 = nullptr;
if (m_exprRetVar != nullptr) // func().member
{
pile3 = pile->AddStack2();
if (pile3->GetState() == 1) // function call is done?
{
if (!m_exprRetVar->Execute(pile3)) return false;
return pj->Return(pile3);
}
}
// CBotStack* pile1 = pile;
int i = 0;
CBotInstr* p = m_parameters;
// evaluates parameters
// and places the values on the stack
// for allow of interruption at any time
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?
2015-12-31 15:10:47 +00:00
pile->SetState(1); // set state to remember that parameters were executed
}
ppVars[i++] = pile->GetVar();
p = p->GetNext();
if ( p == nullptr) break;
}
ppVars[i] = nullptr;
CBotStack* pile2 = pile->AddStack();
if ( pile2->IfStep() ) return false;
if ( !pile2->ExecuteCall(m_nFuncIdent, GetToken(), ppVars, m_typRes)) return false; // interrupt
if (m_exprRetVar != nullptr) // func().member
{
pile3->SetCopyVar( pile2->GetVar() ); // copy the result
pile2->SetVar(nullptr);
pile3->SetState(1); // set call is done
return false; // go back to the top ^^^
}
return pj->Return(pile2); // release the entire stack
}
////////////////////////////////////////////////////////////////////////////////
void CBotInstrCall::RestoreState(CBotStack* &pj, bool bMain)
{
if ( !bMain ) return;
CBotStack* pile = pj->RestoreStack(this);
if ( pile == nullptr ) return;
if (m_exprRetVar != nullptr) // func().member
{
CBotStack* pile3 = pile->AddStack2();
if (pile3->GetState() == 1) // function call is done?
{
m_exprRetVar->RestoreState(pile3, bMain);
return;
}
}
// CBotStack* pile1 = pile;
int i = 0;
CBotVar* ppVars[1000];
CBotInstr* p = m_parameters;
// evaluate parameters
// and place the values on the stack
// for allow of interruption at any time
if ( p != nullptr) while ( true )
{
pile = pile->RestoreStack(); // place on the stack for the results
if ( pile == nullptr ) return;
if ( pile->GetState() == 0 )
{
p->RestoreState(pile, bMain); // interrupt here!
return;
}
ppVars[i++] = pile->GetVar(); // constructs the list of parameters
p = p->GetNext();
if ( p == nullptr) break;
}
ppVars[i] = nullptr;
CBotStack* pile2 = pile->RestoreStack();
if ( pile2 == nullptr ) return;
pile2->RestoreCall(m_nFuncIdent, GetToken(), ppVars);
}
2015-12-26 13:19:24 +00:00
std::string CBotInstrCall::GetDebugData()
{
std::stringstream ss;
ss << m_token.GetString() << std::endl;
//ss << "FuncID = " << m_nFuncIdent << std::endl;
ss << "resultType = " << m_typRes.ToString();
return ss.str();
}
std::map<std::string, CBotInstr*> CBotInstrCall::GetDebugLinks()
{
auto links = CBotInstr::GetDebugLinks();
links["m_parameters"] = m_parameters;
return links;
}
2015-12-26 13:19:24 +00:00
} // namespace CBot