2015-11-11 16:42:10 +00:00
|
|
|
/*
|
|
|
|
* This file is part of the Colobot: Gold Edition source code
|
2020-07-07 08:19:36 +00:00
|
|
|
* Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
|
2015-11-11 16:42:10 +00:00
|
|
|
* 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-27 15:51:57 +00:00
|
|
|
#include <sstream>
|
2015-11-23 20:59:56 +00:00
|
|
|
#include "CBot/CBotInstr/CBotNew.h"
|
2015-11-11 16:42:10 +00:00
|
|
|
|
2015-11-23 20:59:56 +00:00
|
|
|
#include "CBot/CBotStack.h"
|
|
|
|
#include "CBot/CBotCStack.h"
|
|
|
|
#include "CBot/CBotClass.h"
|
2015-11-14 11:56:16 +00:00
|
|
|
|
2016-08-14 20:56:17 +00:00
|
|
|
#include "CBot/CBotInstr/CBotExprRetVar.h"
|
2015-11-23 20:59:56 +00:00
|
|
|
#include "CBot/CBotInstr/CBotInstrUtils.h"
|
2015-11-22 14:47:46 +00:00
|
|
|
|
2015-11-23 20:59:56 +00:00
|
|
|
#include "CBot/CBotVar/CBotVar.h"
|
2015-11-15 22:18:47 +00:00
|
|
|
|
2015-12-26 13:19:24 +00:00
|
|
|
namespace CBot
|
|
|
|
{
|
2015-11-11 16:42:10 +00:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
CBotNew::CBotNew()
|
|
|
|
{
|
2015-12-27 15:51:57 +00:00
|
|
|
m_parameters = nullptr;
|
2017-01-16 18:00:01 +00:00
|
|
|
m_exprRetVar = nullptr;
|
2015-11-11 16:42:10 +00:00
|
|
|
m_nMethodeIdent = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
CBotNew::~CBotNew()
|
|
|
|
{
|
2017-01-16 18:00:01 +00:00
|
|
|
delete m_parameters;
|
|
|
|
delete m_exprRetVar;
|
2015-11-11 16:42:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
CBotInstr* CBotNew::Compile(CBotToken* &p, CBotCStack* pStack)
|
|
|
|
{
|
|
|
|
CBotToken* pp = p;
|
|
|
|
if (!IsOfType(p, ID_NEW)) return nullptr;
|
|
|
|
|
|
|
|
// verifies that the token is a class name
|
2016-06-24 21:03:50 +00:00
|
|
|
if (p->GetType() != TokenTypVar)
|
|
|
|
{
|
|
|
|
pStack->SetError(CBotErrBadNew, p);
|
|
|
|
return nullptr;
|
|
|
|
}
|
2015-11-11 16:42:10 +00:00
|
|
|
|
|
|
|
CBotClass* pClass = CBotClass::Find(p);
|
|
|
|
if (pClass == nullptr)
|
|
|
|
{
|
2015-12-20 18:01:03 +00:00
|
|
|
pStack->SetError(CBotErrBadNew, p);
|
2015-11-11 16:42:10 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
CBotNew* inst = new CBotNew();
|
|
|
|
inst->SetToken(pp);
|
|
|
|
|
2015-12-23 16:37:26 +00:00
|
|
|
inst->m_vartoken = *p;
|
2015-11-11 16:42:10 +00:00
|
|
|
p = p->GetNext();
|
|
|
|
|
2015-12-30 18:13:32 +00:00
|
|
|
// creates the object on the stack
|
2015-11-11 16:42:10 +00:00
|
|
|
// with a pointer to the object
|
|
|
|
CBotVar* pVar = CBotVar::Create("", pClass);
|
|
|
|
|
|
|
|
// do the call of the creator
|
|
|
|
CBotCStack* pStk = pStack->TokenStack();
|
|
|
|
{
|
|
|
|
// check if there are parameters
|
|
|
|
CBotVar* ppVars[1000];
|
2015-12-27 15:51:57 +00:00
|
|
|
inst->m_parameters = CompileParams(p, pStk, ppVars);
|
2015-11-11 16:42:10 +00:00
|
|
|
if (!pStk->IsOk()) goto error;
|
|
|
|
|
|
|
|
// constructor exist?
|
2016-11-11 20:49:27 +00:00
|
|
|
CBotTypResult r = pClass->CompileMethode(&inst->m_vartoken, pVar, ppVars, pStk, inst->m_nMethodeIdent);
|
2021-06-12 02:47:33 +00:00
|
|
|
pStk->DeleteNext(); // release extra stack
|
2015-11-11 16:42:10 +00:00
|
|
|
int typ = r.GetType();
|
|
|
|
|
|
|
|
// if there is no constructor, and no parameters either, it's ok
|
2015-12-27 15:51:57 +00:00
|
|
|
if (typ == CBotErrUndefCall && inst->m_parameters == nullptr) typ = 0;
|
2015-11-11 16:42:10 +00:00
|
|
|
pVar->SetInit(CBotVar::InitType::DEF); // mark the instance as init
|
|
|
|
|
|
|
|
if (typ>20)
|
|
|
|
{
|
2015-12-20 18:16:01 +00:00
|
|
|
pStk->SetError(static_cast<CBotError>(typ), inst->m_vartoken.GetEnd());
|
2015-11-11 16:42:10 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if the constructor does not exist, but there are parameters
|
2015-12-27 15:51:57 +00:00
|
|
|
if (typ<0 && inst->m_parameters != nullptr)
|
2015-11-11 16:42:10 +00:00
|
|
|
{
|
2015-12-20 18:01:03 +00:00
|
|
|
pStk->SetError(CBotErrNoConstruct, &inst->m_vartoken);
|
2015-11-11 16:42:10 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
// makes pointer to the object on the stack
|
|
|
|
pStk->SetVar(pVar);
|
2016-08-14 20:56:17 +00:00
|
|
|
|
|
|
|
pp = p;
|
|
|
|
// chained method ?
|
|
|
|
if (nullptr != (inst->m_exprRetVar = CBotExprRetVar::Compile(p, pStk, true)))
|
|
|
|
{
|
|
|
|
inst->m_exprRetVar->SetToken(pp);
|
2021-06-12 02:47:33 +00:00
|
|
|
pStk->DeleteNext();
|
2016-08-14 20:56:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (pStack->IsOk())
|
|
|
|
return pStack->Return(inst, pStk);
|
2015-11-11 16:42:10 +00:00
|
|
|
}
|
|
|
|
error:
|
|
|
|
delete inst;
|
|
|
|
return pStack->Return(nullptr, pStk);
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool CBotNew::Execute(CBotStack* &pj)
|
|
|
|
{
|
|
|
|
CBotStack* pile = pj->AddStack(this); //main stack
|
|
|
|
|
2016-08-14 20:56:17 +00:00
|
|
|
if (m_exprRetVar != nullptr) // new Class().method()
|
|
|
|
{
|
|
|
|
if (pile->GetState() == 2)
|
|
|
|
{
|
|
|
|
CBotStack* pile3 = pile->AddStack();
|
|
|
|
if (!m_exprRetVar->Execute(pile3)) return false;
|
|
|
|
return pj->Return(pile3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-11 16:42:10 +00:00
|
|
|
if (pile->IfStep()) return false;
|
|
|
|
|
|
|
|
CBotStack* pile1 = pj->AddStack2(); //secondary stack
|
|
|
|
|
|
|
|
CBotVar* pThis = nullptr;
|
|
|
|
|
|
|
|
CBotToken* pt = &m_vartoken;
|
|
|
|
CBotClass* pClass = CBotClass::Find(pt);
|
|
|
|
|
|
|
|
// create the variable "this" pointer type to the stack
|
|
|
|
|
|
|
|
if ( pile->GetState()==0)
|
|
|
|
{
|
|
|
|
// create an instance of the requested class
|
|
|
|
// and initialize the pointer to that object
|
|
|
|
|
|
|
|
|
|
|
|
pThis = CBotVar::Create("this", pClass);
|
|
|
|
pThis->SetUniqNum(-2) ;
|
|
|
|
|
|
|
|
pile1->SetVar(pThis); // place on stack1
|
|
|
|
pile->IncState();
|
|
|
|
}
|
|
|
|
|
|
|
|
// fetch the this pointer if it was interrupted
|
|
|
|
if ( pThis == nullptr)
|
|
|
|
{
|
|
|
|
pThis = pile1->GetVar(); // find the pointer
|
|
|
|
}
|
|
|
|
|
|
|
|
// is there an assignment or parameters (constructor)
|
|
|
|
if ( pile->GetState()==1)
|
|
|
|
{
|
|
|
|
// evaluates the constructor of the instance
|
|
|
|
|
|
|
|
CBotVar* ppVars[1000];
|
|
|
|
CBotStack* pile2 = pile;
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
|
2015-12-27 15:51:57 +00:00
|
|
|
CBotInstr* p = m_parameters;
|
2015-11-11 16:42:10 +00:00
|
|
|
// evaluate the parameters
|
|
|
|
// and places the values on the stack
|
|
|
|
// to be interrupted at any time
|
|
|
|
|
|
|
|
if (p != nullptr) while ( true)
|
|
|
|
{
|
|
|
|
pile2 = pile2->AddStack(); // space on the stack for the result
|
2021-06-12 02:46:23 +00:00
|
|
|
if (pile2->StackOver()) return pj->Return(pile2);
|
2015-11-11 16:42:10 +00:00
|
|
|
if (pile2->GetState() == 0)
|
|
|
|
{
|
|
|
|
if (!p->Execute(pile2)) return false; // interrupted here?
|
|
|
|
pile2->SetState(1);
|
|
|
|
}
|
|
|
|
ppVars[i++] = pile2->GetVar();
|
|
|
|
p = p->GetNext();
|
|
|
|
if ( p == nullptr) break;
|
|
|
|
}
|
|
|
|
ppVars[i] = nullptr;
|
|
|
|
|
2017-01-24 20:19:03 +00:00
|
|
|
if ( !pClass->ExecuteMethode(m_nMethodeIdent, pThis, ppVars, CBotTypResult(CBotTypVoid), pile2, &m_vartoken)) return false; // interrupt
|
2015-11-11 16:42:10 +00:00
|
|
|
|
|
|
|
pThis->ConstructorSet(); // indicates that the constructor has been called
|
|
|
|
}
|
|
|
|
|
2016-08-14 20:56:17 +00:00
|
|
|
if (m_exprRetVar != nullptr) // new Class().method()
|
|
|
|
{
|
|
|
|
pile->AddStack()->Delete(); // release pile2 stack
|
|
|
|
CBotStack* pile3 = pile->AddStack(); // add new stack
|
|
|
|
pile3->SetCopyVar(pThis); // copy the pointer (from pile1)
|
|
|
|
pile1->Delete(); // release secondary stack(pile1)
|
|
|
|
pile->SetState(2);
|
|
|
|
return false; // go back to the top ^^^
|
|
|
|
}
|
|
|
|
|
2015-11-11 16:42:10 +00:00
|
|
|
return pj->Return(pile1); // passes below
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void CBotNew::RestoreState(CBotStack* &pj, bool bMain)
|
|
|
|
{
|
|
|
|
if (!bMain) return;
|
|
|
|
|
|
|
|
CBotStack* pile = pj->RestoreStack(this); //primary stack
|
|
|
|
if (pile == nullptr) return;
|
|
|
|
|
2016-08-14 20:56:17 +00:00
|
|
|
if (m_exprRetVar != nullptr) // new Class().method()
|
|
|
|
{
|
|
|
|
if (pile->GetState() == 2)
|
|
|
|
{
|
|
|
|
CBotStack* pile3 = pile->RestoreStack();
|
|
|
|
m_exprRetVar->RestoreState(pile3, bMain);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-11 16:42:10 +00:00
|
|
|
CBotStack* pile1 = pj->AddStack2(); //secondary stack
|
|
|
|
|
|
|
|
CBotToken* pt = &m_vartoken;
|
|
|
|
CBotClass* pClass = CBotClass::Find(pt);
|
|
|
|
|
|
|
|
// create the variable "this" pointer type to the object
|
|
|
|
|
|
|
|
if ( pile->GetState()==0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
CBotVar* pThis = pile1->GetVar(); // find the pointer
|
|
|
|
pThis->SetUniqNum(-2);
|
|
|
|
|
|
|
|
// is ther an assignment or parameters (constructor)
|
|
|
|
if ( pile->GetState()==1)
|
|
|
|
{
|
|
|
|
// evaluates the constructor of the instance
|
|
|
|
|
|
|
|
CBotVar* ppVars[1000];
|
|
|
|
CBotStack* pile2 = pile;
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
|
2015-12-27 15:51:57 +00:00
|
|
|
CBotInstr* p = m_parameters;
|
2015-11-11 16:42:10 +00:00
|
|
|
// evaluate the parameters
|
|
|
|
// and places the values on the stack
|
|
|
|
// to be interrupted at any time
|
|
|
|
|
|
|
|
if (p != nullptr) while ( true)
|
|
|
|
{
|
|
|
|
pile2 = pile2->RestoreStack(); // space on the stack for the result
|
|
|
|
if (pile2 == nullptr) return;
|
|
|
|
|
|
|
|
if (pile2->GetState() == 0)
|
|
|
|
{
|
|
|
|
p->RestoreState(pile2, bMain); // interrupt here!
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ppVars[i++] = pile2->GetVar();
|
|
|
|
p = p->GetNext();
|
|
|
|
if ( p == nullptr) break;
|
|
|
|
}
|
|
|
|
ppVars[i] = nullptr;
|
|
|
|
|
2016-11-11 20:49:27 +00:00
|
|
|
pClass->RestoreMethode(m_nMethodeIdent, &m_vartoken, pThis, ppVars, pile2); // interrupt here!
|
2015-11-11 16:42:10 +00:00
|
|
|
}
|
|
|
|
}
|
2015-12-26 13:19:24 +00:00
|
|
|
|
2015-12-27 15:51:57 +00:00
|
|
|
std::string CBotNew::GetDebugData()
|
|
|
|
{
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << "ConstructorID = " << m_nMethodeIdent;
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::map<std::string, CBotInstr*> CBotNew::GetDebugLinks()
|
|
|
|
{
|
|
|
|
auto links = CBotInstr::GetDebugLinks();
|
|
|
|
links["m_parameters"] = m_parameters;
|
|
|
|
return links;
|
|
|
|
}
|
|
|
|
|
2015-12-26 13:19:24 +00:00
|
|
|
} // namespace CBot
|