colobot/src/CBot/CBotClass.cpp

840 lines
24 KiB
C++
Raw Normal View History

/*
* This file is part of the Colobot: Gold Edition source code
2015-08-22 14:40:02 +00:00
* 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
*/
2012-08-07 13:46:04 +00:00
// Modules inlcude
#include "CBot/CBotClass.h"
#include "CBot/CBotInstr/CBotNew.h"
#include "CBot/CBotInstr/CBotLeftExprVar.h"
#include "CBot/CBotInstr/CBotTwoOpExpr.h"
#include "CBot/CBotInstr/CBotFunction.h"
#include "CBot/CBotInstr/CBotExpression.h"
#include "CBot/CBotInstr/CBotListArray.h"
#include "CBot/CBotInstr/CBotEmpty.h"
#include "CBot/CBotCall.h"
#include "CBot/CBotStack.h"
#include "CBot/CBotCStack.h"
#include "CBot/CBotUtils.h"
#include "CBot/CBotFileUtils.h"
#include "CBot/CBotCallMethode.h"
#include "CBot/CBotVar/CBotVar.h"
// Local include
// Global include
////////////////////////////////////////////////////////////////////////////////
2015-08-16 10:43:42 +00:00
CBotClass* CBotClass::m_ExClass = nullptr;
2012-08-07 13:46:04 +00:00
////////////////////////////////////////////////////////////////////////////////
CBotClass::CBotClass(const char* name,
CBotClass* pPapa,
bool bIntrinsic)
2012-08-07 13:46:04 +00:00
{
2012-08-08 20:35:17 +00:00
m_pParent = pPapa;
m_name = name;
2015-08-16 10:43:42 +00:00
m_pVar = nullptr;
m_next = nullptr;
m_pCalls = nullptr;
m_pMethod = nullptr;
m_rMaj = nullptr;
2012-08-08 20:35:17 +00:00
m_IsDef = true;
m_bIntrinsic= bIntrinsic;
m_cptLock = 0;
m_cptOne = 0;
2015-08-16 10:43:42 +00:00
m_nbVar = m_pParent == nullptr ? 0 : m_pParent->m_nbVar;
2012-08-07 13:46:04 +00:00
2012-08-08 20:35:17 +00:00
for ( int j= 0; j< 5 ; j++ )
{
2015-08-16 10:43:42 +00:00
m_ProgInLock[j] = nullptr;
2012-08-08 20:35:17 +00:00
}
2012-08-07 13:46:04 +00:00
2012-08-08 20:35:17 +00:00
// is located alone in the list
if (m_ExClass) m_ExClass->m_ExPrev = this;
m_ExNext = m_ExClass;
2015-08-16 10:43:42 +00:00
m_ExPrev = nullptr;
2012-08-08 20:35:17 +00:00
m_ExClass = this;
2012-08-07 13:46:04 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-07 13:46:04 +00:00
CBotClass::~CBotClass()
{
// removes the list of class
2012-08-08 20:35:17 +00:00
if ( m_ExPrev ) m_ExPrev->m_ExNext = m_ExNext;
else m_ExClass = m_ExNext;
2012-08-07 13:46:04 +00:00
2012-08-08 20:35:17 +00:00
if ( m_ExNext ) m_ExNext->m_ExPrev = m_ExPrev;
2015-08-16 10:43:42 +00:00
m_ExPrev = nullptr;
m_ExNext = nullptr;
2012-08-07 13:46:04 +00:00
2012-08-08 20:35:17 +00:00
delete m_pVar;
delete m_pCalls;
delete m_pMethod;
2012-08-07 13:46:04 +00:00
2012-08-08 20:35:17 +00:00
delete m_next; // releases all of them on this level
2012-08-07 13:46:04 +00:00
}
////////////////////////////////////////////////////////////////////////////////
CBotClass* CBotClass::Create(const char* name,
CBotClass* parent,
bool intrinsic)
{
return new CBotClass(name, parent, intrinsic);
}
2012-08-07 13:46:04 +00:00
////////////////////////////////////////////////////////////////////////////////
2012-08-07 13:46:04 +00:00
void CBotClass::Free()
{
2015-08-16 10:43:42 +00:00
while ( m_ExClass != nullptr )
2012-08-08 20:35:17 +00:00
{
delete m_ExClass;
}
2012-08-07 13:46:04 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-07 13:46:04 +00:00
void CBotClass::Purge()
{
2015-08-16 10:43:42 +00:00
if ( this == nullptr ) return;
2012-08-07 13:46:04 +00:00
2012-08-08 20:35:17 +00:00
delete m_pVar;
2015-08-16 10:43:42 +00:00
m_pVar = nullptr;
2012-08-08 20:35:17 +00:00
delete m_pCalls;
2015-08-16 10:43:42 +00:00
m_pCalls = nullptr;
2012-08-08 20:35:17 +00:00
delete m_pMethod;
2015-08-16 10:43:42 +00:00
m_pMethod = nullptr;
2012-08-08 20:35:17 +00:00
m_IsDef = false;
2012-08-07 13:46:04 +00:00
2015-08-16 10:43:42 +00:00
m_nbVar = m_pParent == nullptr ? 0 : m_pParent->m_nbVar;
2012-08-07 13:46:04 +00:00
2012-08-08 20:35:17 +00:00
m_next->Purge();
2015-08-16 10:43:42 +00:00
m_next = nullptr; // no longer belongs to this chain
2012-08-07 13:46:04 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-07 13:46:04 +00:00
bool CBotClass::Lock(CBotProgram* p)
{
2012-08-08 20:35:17 +00:00
int i = m_cptLock++;
if ( i == 0 )
{
m_cptOne = 1;
m_ProgInLock[0] = p;
return true;
}
if ( p == m_ProgInLock[0] )
2012-08-08 20:35:17 +00:00
{
m_cptOne++;
m_cptLock--; // has already been counted
return true;
}
for ( int j = 1 ; j <= i ; j++)
{
if ( p == m_ProgInLock[j] )
{
m_cptLock--;
return false; // already pending
}
}
if ( i < 5 ) // max 5 in query
{
m_ProgInLock[i] = p; // located in a queue
}
else
m_cptLock--;
return false;
2012-08-07 13:46:04 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-07 13:46:04 +00:00
void CBotClass::Unlock()
{
2012-08-08 20:35:17 +00:00
if ( --m_cptOne > 0 ) return ;
2012-08-07 13:46:04 +00:00
2012-08-08 20:35:17 +00:00
int i = --m_cptLock;
if ( i<0 )
{
m_cptLock = 0;
return;
}
2012-08-07 13:46:04 +00:00
2012-08-08 20:35:17 +00:00
for ( int j= 0; j< i ; j++ )
{
m_ProgInLock[j] = m_ProgInLock[j+1];
}
2015-08-17 20:40:52 +00:00
m_ProgInLock[i] = nullptr;
2012-08-07 13:46:04 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-07 13:46:04 +00:00
void CBotClass::FreeLock(CBotProgram* p)
{
2012-08-08 20:35:17 +00:00
CBotClass* pClass = m_ExClass;
2012-08-07 13:46:04 +00:00
2015-08-16 10:43:42 +00:00
while ( pClass != nullptr )
2012-08-08 20:35:17 +00:00
{
if ( p == pClass->m_ProgInLock[0] )
2012-08-08 20:35:17 +00:00
{
pClass->m_cptLock -= pClass->m_cptOne;
pClass->m_cptOne = 0;
}
2012-08-07 13:46:04 +00:00
2012-08-08 20:35:17 +00:00
for ( int j = 1; j < 5 ; j++ )
if ( p == pClass->m_ProgInLock[j] )
2012-08-08 20:35:17 +00:00
pClass->m_cptLock--;
2012-08-07 13:46:04 +00:00
2012-08-08 20:35:17 +00:00
pClass = pClass->m_ExNext;
}
2012-08-07 13:46:04 +00:00
}
////////////////////////////////////////////////////////////////////////////////
bool CBotClass::AddItem(CBotString name,
CBotTypResult type,
int mPrivate)
2012-08-07 13:46:04 +00:00
{
2012-08-08 20:35:17 +00:00
CBotToken token(name, CBotString());
2012-08-11 18:59:35 +00:00
CBotClass* pClass = type.GetClass();
2012-08-07 13:46:04 +00:00
2012-08-08 20:35:17 +00:00
CBotVar* pVar = CBotVar::Create( name, type );
/// pVar->SetUniqNum(CBotVar::NextUniqNum());
pVar->SetPrivate( mPrivate );
2012-08-07 13:46:04 +00:00
2015-08-16 10:43:42 +00:00
if ( pClass != nullptr )
2012-08-08 20:35:17 +00:00
{
// pVar->SetClass(pClass);
if ( type.Eq(CBotTypClass) )
{
// adds a new statement for the object initialization
pVar->m_InitExpr = new CBotNew() ;
2012-08-11 18:59:35 +00:00
CBotToken nom( pClass->GetName() );
2012-08-08 20:35:17 +00:00
pVar->m_InitExpr->SetToken(&nom);
}
}
return AddItem( pVar );
2012-08-07 13:46:04 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-07 13:46:04 +00:00
bool CBotClass::AddItem(CBotVar* pVar)
{
2012-08-08 20:35:17 +00:00
pVar->SetUniqNum(++m_nbVar);
2012-08-07 13:46:04 +00:00
2015-08-16 10:43:42 +00:00
if ( m_pVar == nullptr ) m_pVar = pVar;
2012-08-08 20:35:17 +00:00
else m_pVar->AddNext(pVar);
2012-08-07 13:46:04 +00:00
2012-08-08 20:35:17 +00:00
return true;
2012-08-07 13:46:04 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-07 13:46:04 +00:00
void CBotClass::AddNext(CBotClass* pClass)
{
2012-08-08 20:35:17 +00:00
CBotClass* p = this;
2015-08-16 10:43:42 +00:00
while (p->m_next != nullptr) p = p->m_next;
2012-08-07 13:46:04 +00:00
2012-08-08 20:35:17 +00:00
p->m_next = pClass;
2012-08-07 13:46:04 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-11 18:59:35 +00:00
CBotString CBotClass::GetName()
2012-08-07 13:46:04 +00:00
{
2012-08-08 20:35:17 +00:00
return m_name;
2012-08-07 13:46:04 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-11 18:59:35 +00:00
CBotClass* CBotClass::GetParent()
2012-08-07 13:46:04 +00:00
{
2015-08-16 10:43:42 +00:00
if ( this == nullptr ) return nullptr;
2012-08-08 20:35:17 +00:00
return m_pParent;
2012-08-07 13:46:04 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-07 13:46:04 +00:00
bool CBotClass::IsChildOf(CBotClass* pClass)
{
2012-08-08 20:35:17 +00:00
CBotClass* p = this;
2015-08-16 10:43:42 +00:00
while ( p != nullptr )
2012-08-08 20:35:17 +00:00
{
if ( p == pClass ) return true;
p = p->m_pParent;
}
return false;
2012-08-07 13:46:04 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-11 18:59:35 +00:00
CBotVar* CBotClass::GetVar()
2012-08-07 13:46:04 +00:00
{
2012-08-08 20:35:17 +00:00
return m_pVar;
2012-08-07 13:46:04 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-11 18:59:35 +00:00
CBotVar* CBotClass::GetItem(const char* name)
2012-08-07 13:46:04 +00:00
{
2012-08-08 20:35:17 +00:00
CBotVar* p = m_pVar;
2012-08-07 13:46:04 +00:00
2015-08-16 10:43:42 +00:00
while ( p != nullptr )
2012-08-08 20:35:17 +00:00
{
2012-08-11 18:59:35 +00:00
if ( p->GetName() == name ) return p;
p = p->GetNext();
2012-08-08 20:35:17 +00:00
}
2015-08-16 10:43:42 +00:00
if ( m_pParent != nullptr ) return m_pParent->GetItem(name);
return nullptr;
2012-08-07 13:46:04 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-11 18:59:35 +00:00
CBotVar* CBotClass::GetItemRef(int nIdent)
2012-08-07 13:46:04 +00:00
{
2012-08-08 20:35:17 +00:00
CBotVar* p = m_pVar;
2012-08-07 13:46:04 +00:00
2015-08-16 10:43:42 +00:00
while ( p != nullptr )
2012-08-08 20:35:17 +00:00
{
2012-08-11 18:59:35 +00:00
if ( p->GetUniqNum() == nIdent ) return p;
p = p->GetNext();
2012-08-08 20:35:17 +00:00
}
2015-08-16 10:43:42 +00:00
if ( m_pParent != nullptr ) return m_pParent->GetItemRef(nIdent);
return nullptr;
2012-08-07 13:46:04 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-07 13:46:04 +00:00
bool CBotClass::IsIntrinsic()
{
2012-08-08 20:35:17 +00:00
return m_bIntrinsic;
2012-08-07 13:46:04 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-07 13:46:04 +00:00
CBotClass* CBotClass::Find(CBotToken* &pToken)
{
2012-08-11 18:59:35 +00:00
return Find(pToken->GetString());
2012-08-07 13:46:04 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-07 13:46:04 +00:00
CBotClass* CBotClass::Find(const char* name)
{
2012-08-08 20:35:17 +00:00
CBotClass* p = m_ExClass;
2012-08-07 13:46:04 +00:00
2015-08-16 10:43:42 +00:00
while ( p != nullptr )
2012-08-08 20:35:17 +00:00
{
2012-08-11 18:59:35 +00:00
if ( p->GetName() == name ) return p;
2012-08-08 20:35:17 +00:00
p = p->m_ExNext;
}
2012-08-07 13:46:04 +00:00
2015-08-16 10:43:42 +00:00
return nullptr;
2012-08-07 13:46:04 +00:00
}
////////////////////////////////////////////////////////////////////////////////
bool CBotClass::AddFunction(const char* name,
bool rExec (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception, void* user),
CBotTypResult rCompile (CBotVar* pThis, CBotVar* &pVar))
2012-08-08 20:35:17 +00:00
{
// stores pointers to the two functions
CBotCallMethode* p = m_pCalls;
2015-08-16 10:43:42 +00:00
CBotCallMethode* pp = nullptr;
2012-08-08 20:35:17 +00:00
2015-08-16 10:43:42 +00:00
while ( p != nullptr )
2012-08-08 20:35:17 +00:00
{
2012-08-11 18:59:35 +00:00
if ( name == p->GetName() )
2012-08-08 20:35:17 +00:00
{
2015-08-16 10:43:42 +00:00
if ( pp == nullptr ) m_pCalls = p->m_next;
2012-08-08 20:35:17 +00:00
else pp->m_next = p->m_next;
delete p;
break;
}
pp = p;
p = p->m_next;
}
p = new CBotCallMethode(name, rExec, rCompile);
2015-08-16 10:43:42 +00:00
if (m_pCalls == nullptr) m_pCalls = p;
2012-08-08 20:35:17 +00:00
else m_pCalls->AddNext(p); // added to the list
return true;
2012-08-07 13:46:04 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-07 13:46:04 +00:00
bool CBotClass::AddUpdateFunc( void rMaj ( CBotVar* pThis, void* pUser ) )
{
2012-08-08 20:35:17 +00:00
m_rMaj = rMaj;
return true;
2012-08-07 13:46:04 +00:00
}
////////////////////////////////////////////////////////////////////////////////
CBotTypResult CBotClass::CompileMethode(const char* name,
CBotVar* pThis,
CBotVar** ppParams,
CBotCStack* pStack,
long& nIdent)
2012-08-07 13:46:04 +00:00
{
2012-08-08 20:35:17 +00:00
nIdent = 0; // forget the previous one if necessary
2012-08-07 13:46:04 +00:00
2012-08-08 20:35:17 +00:00
// find the methods declared by AddFunction
2012-08-07 13:46:04 +00:00
2012-08-08 20:35:17 +00:00
CBotTypResult r = m_pCalls->CompileCall(name, pThis, ppParams, pStack, nIdent);
2012-08-11 18:59:35 +00:00
if ( r.GetType() >= 0) return r;
2012-08-07 13:46:04 +00:00
2012-08-08 20:35:17 +00:00
// find the methods declared by user
2012-08-07 13:46:04 +00:00
2012-08-08 20:35:17 +00:00
r = m_pMethod->CompileCall(name, ppParams, nIdent);
2015-08-16 10:43:42 +00:00
if ( r.Eq(TX_UNDEFCALL) && m_pParent != nullptr )
2012-08-08 20:35:17 +00:00
return m_pParent->m_pMethod->CompileCall(name, ppParams, nIdent);
return r;
2012-08-07 13:46:04 +00:00
}
////////////////////////////////////////////////////////////////////////////////
bool CBotClass::ExecuteMethode(long& nIdent,
const char* name,
CBotVar* pThis,
CBotVar** ppParams,
CBotVar* &pResult,
CBotStack* &pStack,
2012-08-08 20:35:17 +00:00
CBotToken* pToken)
2012-08-07 13:46:04 +00:00
{
2012-08-08 20:35:17 +00:00
int ret = m_pCalls->DoCall(nIdent, name, pThis, ppParams, pResult, pStack, pToken);
if (ret>=0) return ret;
2012-08-07 13:46:04 +00:00
2012-08-08 20:35:17 +00:00
ret = m_pMethod->DoCall(nIdent, name, pThis, ppParams, pStack, pToken, this);
if (ret >= 0) return ret;
if (m_pParent != nullptr)
{
ret = m_pParent->m_pCalls->DoCall(nIdent, name, pThis, ppParams, pResult, pStack, pToken);
if (ret >= 0) return ret;
ret = m_pParent->m_pMethod->DoCall(nIdent, name, pThis, ppParams, pStack, pToken, m_pParent);
}
2012-08-08 20:35:17 +00:00
return ret;
2012-08-07 13:46:04 +00:00
}
////////////////////////////////////////////////////////////////////////////////
void CBotClass::RestoreMethode(long& nIdent,
const char* name,
CBotVar* pThis,
CBotVar** ppParams,
CBotStack* &pStack)
2012-08-07 13:46:04 +00:00
{
2012-08-08 20:35:17 +00:00
m_pMethod->RestoreCall(nIdent, name, pThis, ppParams, pStack, this);
2012-08-07 13:46:04 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-07 13:46:04 +00:00
bool CBotClass::SaveStaticState(FILE* pf)
{
2012-08-08 20:35:17 +00:00
if (!WriteWord( pf, CBOTVERSION*2)) return false;
2012-08-07 13:46:04 +00:00
2012-08-08 20:35:17 +00:00
// saves the state of static variables in classes
CBotClass* p = m_ExClass;
2012-08-07 13:46:04 +00:00
2015-08-16 10:43:42 +00:00
while ( p != nullptr )
2012-08-08 20:35:17 +00:00
{
if (!WriteWord( pf, 1)) return false;
// save the name of the class
2012-08-11 18:59:35 +00:00
if (!WriteString( pf, p->GetName() )) return false;
2012-08-07 13:46:04 +00:00
2012-08-11 18:59:35 +00:00
CBotVar* pv = p->GetVar();
2015-08-16 10:43:42 +00:00
while( pv != nullptr )
2012-08-08 20:35:17 +00:00
{
if ( pv->IsStatic() )
{
if (!WriteWord( pf, 1)) return false;
2012-08-11 18:59:35 +00:00
if (!WriteString( pf, pv->GetName() )) return false;
2012-08-07 13:46:04 +00:00
2012-08-08 20:35:17 +00:00
if ( !pv->Save0State(pf)) return false; // common header
if ( !pv->Save1State(pf) ) return false; // saves as the child class
if ( !WriteWord( pf, 0)) return false;
}
2012-08-11 18:59:35 +00:00
pv = pv->GetNext();
2012-08-08 20:35:17 +00:00
}
2012-08-07 13:46:04 +00:00
2012-08-08 20:35:17 +00:00
if (!WriteWord( pf, 0)) return false;
p = p->m_ExNext;
}
2012-08-07 13:46:04 +00:00
2012-08-08 20:35:17 +00:00
if (!WriteWord( pf, 0)) return false;
return true;
2012-08-07 13:46:04 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-07 13:46:04 +00:00
bool CBotClass::RestoreStaticState(FILE* pf)
{
2012-08-08 20:35:17 +00:00
CBotString ClassName, VarName;
CBotClass* pClass;
unsigned short w;
2012-08-07 13:46:04 +00:00
2012-08-08 20:35:17 +00:00
if (!ReadWord( pf, w )) return false;
if ( w != CBOTVERSION*2 ) return false;
2012-08-07 13:46:04 +00:00
2012-08-08 20:35:17 +00:00
while (true)
{
if (!ReadWord( pf, w )) return false;
if ( w == 0 ) return true;
2012-08-07 13:46:04 +00:00
2012-08-08 20:35:17 +00:00
if (!ReadString( pf, ClassName )) return false;
pClass = Find(ClassName);
2012-08-07 13:46:04 +00:00
2012-08-08 20:35:17 +00:00
while (true)
{
if (!ReadWord( pf, w )) return false;
if ( w == 0 ) break;
2012-08-07 13:46:04 +00:00
2015-08-16 10:43:42 +00:00
CBotVar* pVar = nullptr;
CBotVar* pv = nullptr;
2012-08-07 13:46:04 +00:00
2012-08-08 20:35:17 +00:00
if (!ReadString( pf, VarName )) return false;
2015-08-16 10:43:42 +00:00
if ( pClass != nullptr ) pVar = pClass->GetItem(VarName);
2012-08-07 13:46:04 +00:00
if (!CBotVar::RestoreState(pf, pv)) return false; // the temp variable
2012-08-07 13:46:04 +00:00
2015-08-16 10:43:42 +00:00
if ( pVar != nullptr ) pVar->Copy(pv);
2012-08-08 20:35:17 +00:00
delete pv;
}
}
return true;
2012-08-07 13:46:04 +00:00
}
////////////////////////////////////////////////////////////////////////////////
bool CBotClass::CheckCall(CBotToken* &pToken,
CBotDefParam* pParam)
2012-08-07 13:46:04 +00:00
{
2012-08-11 18:59:35 +00:00
CBotString name = pToken->GetString();
2012-08-07 13:46:04 +00:00
2012-08-08 20:35:17 +00:00
if ( CBotCall::CheckCall(name) ) return true;
2012-08-07 13:46:04 +00:00
2012-08-08 20:35:17 +00:00
CBotFunction* pp = m_pMethod;
2015-08-16 10:43:42 +00:00
while ( pp != nullptr )
2012-08-08 20:35:17 +00:00
{
2012-08-11 18:59:35 +00:00
if ( pToken->GetString() == pp->GetName() )
2012-08-08 20:35:17 +00:00
{
// are their parameters exactly the same?
if ( pp->CheckParam( pParam ) )
return true;
}
pp = pp->Next();
}
2012-08-07 13:46:04 +00:00
2012-08-08 20:35:17 +00:00
return false;
2012-08-07 13:46:04 +00:00
}
////////////////////////////////////////////////////////////////////////////////
CBotClass* CBotClass::Compile1(CBotToken* &p, CBotCStack* pStack)
{
if ( !IsOfType(p, ID_PUBLIC) )
{
pStack->SetError(TX_NOPUBLIC, p);
return nullptr;
}
if ( !IsOfType(p, ID_CLASS) ) return nullptr;
CBotString name = p->GetString();
CBotClass* pOld = CBotClass::Find(name);
if ( pOld != nullptr && pOld->m_IsDef )
{
pStack->SetError( TX_REDEFCLASS, p );
return nullptr;
}
// a name of the class is there?
if (IsOfType(p, TokenTypVar))
{
CBotClass* pPapa = nullptr;
if ( IsOfType( p, ID_EXTENDS ) )
{
CBotString name = p->GetString();
pPapa = CBotClass::Find(name);
if (!IsOfType(p, TokenTypVar) || pPapa == nullptr )
{
pStack->SetError( TX_NOCLASS, p );
return nullptr;
}
}
CBotClass* classe = (pOld == nullptr) ? new CBotClass(name, pPapa) : pOld;
classe->Purge(); // emptythe old definitions
classe->m_IsDef = false; // current definition
if ( !IsOfType( p, ID_OPBLK) )
{
pStack->SetError(TX_OPENBLK, p);
return nullptr;
}
while ( pStack->IsOk() && !IsOfType( p, ID_CLBLK ) )
{
classe->CompileDefItem(p, pStack, false);
}
if (pStack->IsOk()) return classe;
}
pStack->SetError(TX_ENDOF, p);
return nullptr;
}
////////////////////////////////////////////////////////////////////////////////
bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
{
bool bStatic = false;
int mProtect = PR_PUBLIC;
bool bSynchro = false;
while (IsOfType(p, ID_SEP)) ;
CBotTypResult type( -1 );
if ( IsOfType(p, ID_SYNCHO) ) bSynchro = true;
CBotToken* pBase = p;
if ( IsOfType(p, ID_STATIC) ) bStatic = true;
if ( IsOfType(p, ID_PUBLIC) ) mProtect = PR_PUBLIC;
if ( IsOfType(p, ID_PRIVATE) ) mProtect = PR_PRIVATE;
if ( IsOfType(p, ID_PROTECTED) ) mProtect = PR_PROTECT;
if ( IsOfType(p, ID_STATIC) ) bStatic = true;
// CBotClass* pClass = nullptr;
type = TypeParam(p, pStack); // type of the result
if ( type.Eq(-1) )
{
pStack->SetError(TX_NOTYP, p);
return false;
}
while (pStack->IsOk())
{
CBotToken* pp = p;
IsOfType(p, ID_NOT); // skips ~ eventual (destructor)
if (IsOfType(p, TokenTypVar))
{
CBotInstr* limites = nullptr;
while ( IsOfType( p, ID_OPBRK ) ) // a table?
{
CBotInstr* i = nullptr;
if ( p->GetType() != ID_CLBRK )
i = CBotExpression::Compile( p, pStack ); // expression for the value
else
i = new CBotEmpty(); // special if not a formula
type = CBotTypResult(CBotTypArrayPointer, type);
if (!pStack->IsOk() || !IsOfType( p, ID_CLBRK ) )
{
pStack->SetError(TX_CLBRK, p->GetStart());
return false;
}
/* CBotVar* pv = pStack->GetVar();
if ( pv->GetType()>= CBotTypBoolean )
{
pStack->SetError(TX_BADTYPE, p->GetStart());
return false;
}*/
if (limites == nullptr) limites = i;
else limites->AddNext3(i);
}
if ( p->GetType() == ID_OPENPAR )
{
if ( !bSecond )
{
p = pBase;
CBotFunction* f =
CBotFunction::Compile1(p, pStack, this);
if ( f == nullptr ) return false;
if (m_pMethod == nullptr) m_pMethod = f;
else m_pMethod->AddNext(f);
}
else
{
// return a method precompiled in pass 1
CBotFunction* pf = m_pMethod;
CBotFunction* prev = nullptr;
while ( pf != nullptr )
{
if (pf->GetName() == pp->GetString()) break;
prev = pf;
pf = pf->Next();
}
bool bConstructor = (pp->GetString() == GetName());
CBotCStack* pile = pStack->TokenStack(nullptr, true);
// make "this" known
CBotToken TokenThis(CBotString("this"), CBotString());
CBotVar* pThis = CBotVar::Create(&TokenThis, CBotTypResult( CBotTypClass, this ) );
pThis->SetUniqNum(-2);
pile->AddVar(pThis);
if ( m_pParent )
{
// makes "super" known
CBotToken TokenSuper(CBotString("super"), CBotString());
CBotVar* pThis = CBotVar::Create(&TokenSuper, CBotTypResult( CBotTypClass, m_pParent ) );
pThis->SetUniqNum(-3);
pile->AddVar(pThis);
}
// int num = 1;
CBotClass* my = this;
while (my != nullptr)
{
// places a copy of variables of a class (this) on a stack
CBotVar* pv = my->m_pVar;
while (pv != nullptr)
{
CBotVar* pcopy = CBotVar::Create(pv);
CBotVar::InitType initType = CBotVar::InitType::UNDEF;
if (!bConstructor || pv->IsStatic())
initType = CBotVar::InitType::DEF;
pcopy->SetInit(initType);
pcopy->SetUniqNum(pv->GetUniqNum());
pile->AddVar(pcopy);
pv = pv->GetNext();
}
my = my->m_pParent;
}
// compiles a method
p = pBase;
CBotFunction* f =
CBotFunction::Compile(p, pile, nullptr/*, false*/);
if ( f != nullptr )
{
f->m_pProg = pStack->GetBotCall();
f->m_bSynchro = bSynchro;
// replaces the element in the chain
f->m_next = pf->m_next;
pf->m_next = nullptr;
delete pf;
if (prev == nullptr) m_pMethod = f;
else prev->m_next = f;
}
pStack->Return(nullptr, pile);
}
return pStack->IsOk();
}
// definition of an element
if (type.Eq(0))
{
pStack->SetError(TX_ENDOF, p);
return false;
}
CBotInstr* i = nullptr;
if ( IsOfType(p, ID_ASS ) )
{
if ( type.Eq(CBotTypArrayPointer) )
{
i = CBotListArray::Compile(p, pStack, type.GetTypElem());
}
else
{
// it has an assignmet to calculate
i = CBotTwoOpExpr::Compile(p, pStack);
}
if ( !pStack->IsOk() ) return false;
}
if ( !bSecond )
{
CBotVar* pv = CBotVar::Create(pp->GetString(), type);
pv -> SetStatic( bStatic );
pv -> SetPrivate( mProtect );
AddItem( pv );
pv->m_InitExpr = i;
pv->m_LimExpr = limites;
if ( pv->IsStatic() && pv->m_InitExpr != nullptr )
{
CBotStack* pile = CBotStack::FirstStack(); // independent stack
while(pile->IsOk() && !pv->m_InitExpr->Execute(pile)); // evaluates the expression without timer
pv->SetVal( pile->GetVar() ) ;
pile->Delete();
}
}
else
delete i;
if ( IsOfType(p, ID_COMMA) ) continue;
if ( IsOfType(p, ID_SEP) ) break;
}
pStack->SetError(TX_ENDOF, p);
}
return pStack->IsOk();
}
////////////////////////////////////////////////////////////////////////////////
CBotClass* CBotClass::Compile(CBotToken* &p, CBotCStack* pStack)
{
if ( !IsOfType(p, ID_PUBLIC) ) return nullptr;
if ( !IsOfType(p, ID_CLASS) ) return nullptr;
CBotString name = p->GetString();
// a name for the class is there?
if (IsOfType(p, TokenTypVar))
{
// the class was created by Compile1
CBotClass* pOld = CBotClass::Find(name);
if ( IsOfType( p, ID_EXTENDS ) )
{
// TODO: Not sure how correct is that - I have no idea how the precompilation (Compile1 method) works ~krzys_h
CBotString name = p->GetString();
CBotClass* pPapa = CBotClass::Find(name);
if (!IsOfType(p, TokenTypVar) || pPapa == nullptr)
{
pStack->SetError( TX_NOCLASS, p );
return nullptr;
}
pOld->m_pParent = pPapa;
}
else
{
if (pOld != nullptr)
{
pOld->m_pParent = nullptr;
}
}
IsOfType( p, ID_OPBLK); // necessarily
while ( pStack->IsOk() && !IsOfType( p, ID_CLBLK ) )
{
pOld->CompileDefItem(p, pStack, true);
}
pOld->m_IsDef = true; // complete definition
if (pStack->IsOk()) return pOld;
}
pStack->SetError(TX_ENDOF, p);
return nullptr;
}