282 lines
9.1 KiB
C++
282 lines
9.1 KiB
C++
/*
|
|
* This file is part of the Colobot: Gold Edition source code
|
|
* Copyright (C) 2001-2015, 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
|
|
*/
|
|
|
|
// Modules inlcude
|
|
#include "CBotInstrMethode.h"
|
|
|
|
#include "CBotInstr/CBotInstrUtils.h"
|
|
|
|
#include "CBotStack.h"
|
|
#include "CBotCStack.h"
|
|
#include "CBotClass.h"
|
|
|
|
#include "CBotVar/CBotVar.h"
|
|
|
|
// Local include
|
|
|
|
// Global include
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
CBotInstrMethode::CBotInstrMethode()
|
|
{
|
|
m_Parameters = nullptr;
|
|
m_MethodeIdent = 0;
|
|
name = "CBotInstrMethode";
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
CBotInstrMethode::~CBotInstrMethode()
|
|
{
|
|
delete m_Parameters;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
CBotInstr* CBotInstrMethode::Compile(CBotToken* &p, CBotCStack* pStack, CBotVar* var)
|
|
{
|
|
CBotInstrMethode* inst = new CBotInstrMethode();
|
|
inst->SetToken(p); // corresponding token
|
|
|
|
if (nullptr != var)
|
|
{
|
|
CBotToken* pp = p;
|
|
p = p->GetNext();
|
|
|
|
if (p->GetType() == ID_OPENPAR)
|
|
{
|
|
inst->m_NomMethod = pp->GetString();
|
|
|
|
// compiles the list of parameters
|
|
CBotVar* ppVars[1000];
|
|
inst->m_Parameters = CompileParams(p, pStack, ppVars);
|
|
|
|
if (pStack->IsOk())
|
|
{
|
|
CBotClass* pClass = var->GetClass(); // pointer to the class
|
|
inst->m_ClassName = pClass->GetName(); // name of the class
|
|
CBotTypResult r = pClass->CompileMethode(inst->m_NomMethod, var, ppVars,
|
|
pStack, inst->m_MethodeIdent);
|
|
delete pStack->TokenStack(); // release parameters on the stack
|
|
inst->m_typRes = r;
|
|
|
|
if (inst->m_typRes.GetType() > 20)
|
|
{
|
|
pStack->SetError(inst->m_typRes.GetType(), pp);
|
|
delete inst;
|
|
return nullptr;
|
|
}
|
|
// put the result on the stack to have something
|
|
if (inst->m_typRes.GetType() > 0)
|
|
{
|
|
CBotVar* pResult = CBotVar::Create("", inst->m_typRes);
|
|
if (inst->m_typRes.Eq(CBotTypClass))
|
|
{
|
|
pResult->SetClass(inst->m_typRes.GetClass());
|
|
}
|
|
pStack->SetVar(pResult);
|
|
}
|
|
return inst;
|
|
}
|
|
delete inst;
|
|
return nullptr;
|
|
}
|
|
}
|
|
pStack->SetError(1234, p);
|
|
delete inst;
|
|
return nullptr;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
bool CBotInstrMethode::ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* prevToken, bool bStep, bool bExtend)
|
|
{
|
|
CBotVar* ppVars[1000];
|
|
CBotStack* pile1 = pj->AddStack(this, true); // a place for the copy of This
|
|
|
|
if (pVar->GetPointer() == nullptr)
|
|
{
|
|
pj->SetError(TX_NULLPT, prevToken);
|
|
}
|
|
|
|
if (pile1->IfStep()) return false;
|
|
|
|
CBotStack* pile2 = pile1->AddStack(); // for the next parameters
|
|
|
|
if ( pile1->GetState() == 0)
|
|
{
|
|
CBotVar* pThis = CBotVar::Create(pVar);
|
|
pThis->Copy(pVar);
|
|
// this value should be taken before the evaluation parameters
|
|
// Test.Action (Test = Other);
|
|
// action must act on the value before test = Other!
|
|
|
|
pThis->SetName("this");
|
|
pThis->SetUniqNum(-2);
|
|
pile1->AddVar(pThis);
|
|
pile1->IncState();
|
|
}
|
|
int i = 0;
|
|
|
|
CBotInstr* p = m_Parameters;
|
|
// evaluate the parameters
|
|
// and places the values on the stack
|
|
// to be interrupted at any time
|
|
|
|
if (p != nullptr) while ( true)
|
|
{
|
|
if (pile2->GetState() == 0)
|
|
{
|
|
if (!p->Execute(pile2)) return false; // interrupted here?
|
|
if (!pile2->SetState(1)) return false; // special mark to recognize parameters
|
|
}
|
|
ppVars[i++] = pile2->GetVar(); // construct the list of pointers
|
|
pile2 = pile2->AddStack(); // space on the stack for the result
|
|
p = p->GetNext();
|
|
if ( p == nullptr) break;
|
|
}
|
|
ppVars[i] = nullptr;
|
|
|
|
CBotClass* pClass = CBotClass::Find(m_ClassName);
|
|
CBotVar* pThis = pile1->FindVar(-2);
|
|
CBotVar* pResult = nullptr;
|
|
if (m_typRes.GetType() > 0) pResult = CBotVar::Create("", m_typRes);
|
|
if (m_typRes.Eq(CBotTypClass))
|
|
{
|
|
pResult->SetClass(m_typRes.GetClass());
|
|
}
|
|
CBotVar* pRes = pResult;
|
|
|
|
if ( !pClass->ExecuteMethode(m_MethodeIdent, m_NomMethod,
|
|
pThis, ppVars,
|
|
pResult, pile2, GetToken())) return false;
|
|
if (pRes != pResult) delete pRes;
|
|
|
|
pVar = nullptr; // does not return value for this
|
|
return pj->Return(pile2); // release the entire stack
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void CBotInstrMethode::RestoreStateVar(CBotStack* &pile, bool bMain)
|
|
{
|
|
if (!bMain) return;
|
|
|
|
CBotVar* ppVars[1000];
|
|
CBotStack* pile1 = pile->RestoreStack(this); // place for the copy of This
|
|
if (pile1 == nullptr) return;
|
|
|
|
CBotStack* pile2 = pile1->RestoreStack(); // and for the parameters coming
|
|
if (pile2 == nullptr) return;
|
|
|
|
CBotVar* pThis = pile1->FindVar("this");
|
|
pThis->SetUniqNum(-2);
|
|
|
|
int i = 0;
|
|
|
|
CBotInstr* p = m_Parameters;
|
|
// evaluate the parameters
|
|
// and places the values on the stack
|
|
// to be interrupted at any time
|
|
|
|
if (p != nullptr) while ( true)
|
|
{
|
|
if (pile2->GetState() == 0)
|
|
{
|
|
p->RestoreState(pile2, true); // interrupted here!
|
|
return;
|
|
}
|
|
ppVars[i++] = pile2->GetVar(); // construct the list of pointers
|
|
pile2 = pile2->RestoreStack();
|
|
if (pile2 == nullptr) return;
|
|
|
|
p = p->GetNext();
|
|
if ( p == nullptr) break;
|
|
}
|
|
ppVars[i] = nullptr;
|
|
|
|
CBotClass* pClass = CBotClass::Find(m_ClassName);
|
|
// CBotVar* pResult = nullptr;
|
|
|
|
// CBotVar* pRes = pResult;
|
|
|
|
pClass->RestoreMethode(m_MethodeIdent, m_NomMethod,
|
|
pThis, ppVars, pile2);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
bool CBotInstrMethode::Execute(CBotStack* &pj)
|
|
{
|
|
CBotVar* ppVars[1000];
|
|
CBotStack* pile1 = pj->AddStack(this, true); // place for the copy of This
|
|
|
|
if (pile1->IfStep()) return false;
|
|
|
|
CBotStack* pile2 = pile1->AddStack(); // and for the parameters coming
|
|
|
|
if ( pile1->GetState() == 0)
|
|
{
|
|
CBotVar* pThis = pile1->CopyVar(m_token);
|
|
// this value should be taken before the evaluation parameters
|
|
// Test.Action (Test = Other);
|
|
// Action must act on the value before test = Other!
|
|
pThis->SetName("this");
|
|
pile1->AddVar(pThis);
|
|
pile1->IncState();
|
|
}
|
|
int i = 0;
|
|
|
|
CBotInstr* p = m_Parameters;
|
|
// evaluate the parameters
|
|
// and places the values on the stack
|
|
// to be interrupted at any time
|
|
if (p != nullptr) while ( true)
|
|
{
|
|
if (pile2->GetState() == 0)
|
|
{
|
|
if (!p->Execute(pile2)) return false; // interrupted here?
|
|
if (!pile2->SetState(1)) return false; // special mark to recognize parameters
|
|
}
|
|
ppVars[i++] = pile2->GetVar(); // construct the list of pointers
|
|
pile2 = pile2->AddStack(); // space on the stack for the results
|
|
p = p->GetNext();
|
|
if ( p == nullptr) break;
|
|
}
|
|
ppVars[i] = nullptr;
|
|
|
|
CBotClass* pClass = CBotClass::Find(m_ClassName);
|
|
CBotVar* pThis = pile1->FindVar("this");
|
|
CBotVar* pResult = nullptr;
|
|
if (m_typRes.GetType()>0) pResult = CBotVar::Create("", m_typRes);
|
|
if (m_typRes.Eq(CBotTypClass))
|
|
{
|
|
pResult->SetClass(m_typRes.GetClass());
|
|
}
|
|
CBotVar* pRes = pResult;
|
|
|
|
if ( !pClass->ExecuteMethode(m_MethodeIdent, m_NomMethod,
|
|
pThis, ppVars,
|
|
pResult, pile2, GetToken())) return false; // interupted
|
|
|
|
// set the new value of this in place of the old variable
|
|
CBotVar* old = pile1->FindVar(m_token);
|
|
old->Copy(pThis, false);
|
|
|
|
if (pRes != pResult) delete pRes;
|
|
|
|
return pj->Return(pile2); // release the entire stack
|
|
}
|