colobot/src/CBot/CBotInstr/CBotFunction.cpp

1440 lines
46 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-08 00:01:06 +00:00
// Modules inlcude
#include "CBotFunction.h"
2012-08-08 00:01:06 +00:00
#include "CBot.h"
#include "CBotInstr/CBotBlock.h"
#include "CBotInstr/CBotTwoOpExpr.h"
#include "CBotInstr/CBotExpression.h"
#include "CBotInstr/CBotEmpty.h"
#include "CBotInstr/CBotListArray.h"
#include "CBotStack.h"
#include "CBotClass.h"
// Local include
// Global include
2013-11-25 19:03:06 +00:00
#include <cassert>
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
CBotFunction::CBotFunction()
{
2015-08-16 10:43:42 +00:00
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
2012-08-08 20:35:17 +00:00
m_bExtern = false; // function not extern
2015-08-16 10:43:42 +00:00
m_nextpublic = nullptr;
m_prevpublic = nullptr;
m_pProg = nullptr;
2012-08-08 20:35:17 +00:00
// m_nThisIdent = 0;
m_nFuncIdent = 0;
m_bSynchro = false;
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2015-08-16 10:43:42 +00:00
CBotFunction* CBotFunction::m_listPublic = nullptr;
2012-08-08 00:01:06 +00:00
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
CBotFunction::~CBotFunction()
{
2012-08-08 20:35:17 +00:00
delete m_Param; // empty parameter list
delete m_Block; // the instruction block
delete m_next;
// remove public list if there is
if ( m_bPublic )
{
2015-08-16 10:43:42 +00:00
if ( m_nextpublic != nullptr )
2012-08-08 20:35:17 +00:00
{
m_nextpublic->m_prevpublic = m_prevpublic;
}
2015-08-16 10:43:42 +00:00
if ( m_prevpublic != nullptr)
2012-08-08 20:35:17 +00:00
{
m_prevpublic->m_nextpublic = m_nextpublic;
}
else
{
// if prev = next = null may not be in the list!
if ( m_listPublic == this ) m_listPublic = m_nextpublic;
}
}
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
bool CBotFunction::IsPublic()
{
2012-08-08 20:35:17 +00:00
return m_bPublic;
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
bool CBotFunction::IsExtern()
{
2012-08-08 20:35:17 +00:00
return m_bExtern;
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
bool CBotFunction::GetPosition(int& start, int& stop, CBotGet modestart, CBotGet modestop)
{
2012-08-11 18:59:35 +00:00
start = m_extern.GetStart();
stop = m_closeblk.GetEnd();
2012-08-08 20:35:17 +00:00
if (modestart == GetPosExtern)
{
2012-08-11 18:59:35 +00:00
start = m_extern.GetStart();
2012-08-08 20:35:17 +00:00
}
if (modestop == GetPosExtern)
{
2012-08-11 18:59:35 +00:00
stop = m_extern.GetEnd();
2012-08-08 20:35:17 +00:00
}
if (modestart == GetPosNom)
{
2012-08-11 18:59:35 +00:00
start = m_token.GetStart();
2012-08-08 20:35:17 +00:00
}
if (modestop == GetPosNom)
{
2012-08-11 18:59:35 +00:00
stop = m_token.GetEnd();
2012-08-08 20:35:17 +00:00
}
if (modestart == GetPosParam)
{
2012-08-11 18:59:35 +00:00
start = m_openpar.GetStart();
2012-08-08 20:35:17 +00:00
}
if (modestop == GetPosParam)
{
2012-08-11 18:59:35 +00:00
stop = m_closepar.GetEnd();
2012-08-08 20:35:17 +00:00
}
if (modestart == GetPosBloc)
{
2012-08-11 18:59:35 +00:00
start = m_openblk.GetStart();
2012-08-08 20:35:17 +00:00
}
if (modestop == GetPosBloc)
{
2012-08-11 18:59:35 +00:00
stop = m_closeblk.GetEnd();
2012-08-08 20:35:17 +00:00
}
return true;
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 20:35:17 +00:00
CBotTypResult ArrayType(CBotToken* &p, CBotCStack* pile, CBotTypResult type)
2012-08-08 00:01:06 +00:00
{
2012-08-08 20:35:17 +00:00
while ( IsOfType( p, ID_OPBRK ) )
{
if ( !IsOfType( p, ID_CLBRK ) )
{
2012-08-11 18:59:35 +00:00
pile->SetError(TX_CLBRK, p->GetStart());
2012-08-08 20:35:17 +00:00
return CBotTypResult( -1 );
}
type = CBotTypResult( CBotTypArrayPointer, type );
}
return type;
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 20:35:17 +00:00
CBotTypResult TypeParam(CBotToken* &p, CBotCStack* pile)
2012-08-08 00:01:06 +00:00
{
2015-08-16 10:43:42 +00:00
CBotClass* pClass = nullptr;
2012-08-08 20:35:17 +00:00
2012-08-11 18:59:35 +00:00
switch (p->GetType())
2012-08-08 20:35:17 +00:00
{
case ID_INT:
2012-08-11 18:59:35 +00:00
p = p->GetNext();
2012-08-08 20:35:17 +00:00
return ArrayType(p, pile, CBotTypResult( CBotTypInt ));
case ID_FLOAT:
2012-08-11 18:59:35 +00:00
p = p->GetNext();
2012-08-08 20:35:17 +00:00
return ArrayType(p, pile, CBotTypResult( CBotTypFloat ));
case ID_BOOLEAN:
case ID_BOOL:
2012-08-11 18:59:35 +00:00
p = p->GetNext();
2012-08-08 20:35:17 +00:00
return ArrayType(p, pile, CBotTypResult( CBotTypBoolean ));
case ID_STRING:
2012-08-11 18:59:35 +00:00
p = p->GetNext();
2012-08-08 20:35:17 +00:00
return ArrayType(p, pile, CBotTypResult( CBotTypString ));
case ID_VOID:
2012-08-11 18:59:35 +00:00
p = p->GetNext();
2012-08-08 20:35:17 +00:00
return CBotTypResult( 0 );
case TokenTypVar:
pClass = CBotClass::Find(p);
2015-08-16 10:43:42 +00:00
if ( pClass != nullptr)
2012-08-08 20:35:17 +00:00
{
2012-08-11 18:59:35 +00:00
p = p->GetNext();
return ArrayType(p, pile,
pClass->IsIntrinsic() ?
CBotTypResult( CBotTypIntrinsic, pClass ) :
2012-08-08 20:35:17 +00:00
CBotTypResult( CBotTypPointer, pClass ) );
}
}
return CBotTypResult( -1 );
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
CBotFunction* CBotFunction::Compile(CBotToken* &p, CBotCStack* pStack, CBotFunction* finput, bool bLocal)
{
2012-08-08 20:35:17 +00:00
CBotToken* pp;
CBotFunction* func = finput;
2015-08-16 10:43:42 +00:00
if ( func == nullptr ) func = new CBotFunction();
2012-08-08 20:35:17 +00:00
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
2012-08-11 18:59:35 +00:00
if (func->m_retTyp.GetType() >= 0)
2012-08-08 20:35:17 +00:00
{
CBotToken* pp = p;
func->m_token = *p;
if ( IsOfType(p, ID_NOT) )
{
CBotToken d(CBotString("~") + p->GetString());
2012-08-08 20:35:17 +00:00
func->m_token = d;
}
// un nom de fonction est-il là ?
if (IsOfType(p, TokenTypVar))
{
if ( IsOfType( p, ID_DBLDOTS ) ) // method for a class
{
2012-08-11 18:59:35 +00:00
func->m_MasterClass = pp->GetString();
2012-08-08 20:35:17 +00:00
CBotClass* pClass = CBotClass::Find(pp);
2015-08-16 10:43:42 +00:00
if ( pClass == nullptr ) goto bad;
2012-08-08 20:35:17 +00:00
// pp = p;
func->m_token = *p;
if (!IsOfType(p, TokenTypVar)) goto bad;
}
func->m_openpar = p;
func->m_Param = CBotDefParam::Compile( p, pStk );
2012-08-11 18:59:35 +00:00
func->m_closepar = p->GetPrev();
2012-08-08 20:35:17 +00:00
if (pStk->IsOk())
{
pStk->SetRetType(func->m_retTyp); // for knowledge what type returns
if (!func->m_MasterClass.IsEmpty())
{
// return "this" known
CBotVar* pThis = CBotVar::Create("this", CBotTypResult( CBotTypClass, func->m_MasterClass ));
pThis->SetInit(CBotVar::InitType::IS_POINTER);
2012-08-08 20:35:17 +00:00
// 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
2012-08-11 18:59:35 +00:00
CBotVar* pv = pThis->GetItemList();
2012-08-08 20:35:17 +00:00
// int num = 1;
2015-08-16 10:43:42 +00:00
while (pv != nullptr)
2012-08-08 20:35:17 +00:00
{
CBotVar* pcopy = CBotVar::Create(pv);
// pcopy->SetInit(2);
pcopy->Copy(pv);
2012-08-11 18:59:35 +00:00
pcopy->SetPrivate(pv->GetPrivate());
// pcopy->SetUniqNum(pv->GetUniqNum()); //num++);
2012-08-08 20:35:17 +00:00
pStk->AddVar(pcopy);
2012-08-11 18:59:35 +00:00
pv = pv->GetNext();
2012-08-08 20:35:17 +00:00
}
}
// and compiles the following instruction block
2012-08-08 20:35:17 +00:00
func->m_openblk = p;
func->m_Block = CBotBlock::Compile(p, pStk, false);
2012-08-11 18:59:35 +00:00
func->m_closeblk = p->GetPrev();
2012-08-08 20:35:17 +00:00
if ( pStk->IsOk() )
{
if ( func->m_bPublic ) // public function, return known for all
{
CBotFunction::AddPublic(func);
}
return pStack->ReturnFunc(func, pStk);
}
}
}
2012-08-08 00:01:06 +00:00
bad:
2012-08-08 20:35:17 +00:00
pStk->SetError(TX_NOFONC, p);
}
pStk->SetError(TX_NOTYP, p);
2015-08-16 10:43:42 +00:00
if ( finput == nullptr ) delete func;
return pStack->ReturnFunc(nullptr, pStk);
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 20:35:17 +00:00
CBotFunction* CBotFunction::Compile1(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass)
2012-08-08 00:01:06 +00:00
{
2012-08-08 20:35:17 +00:00
CBotFunction* func = new CBotFunction();
func->m_nFuncIdent = CBotVar::NextUniqNum();
2012-08-08 20:35:17 +00:00
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
2012-08-11 18:59:35 +00:00
if (func->m_retTyp.GetType() >= 0)
2012-08-08 20:35:17 +00:00
{
CBotToken* pp = p;
func->m_token = *p;
// un nom de fonction est-il là ?
if (IsOfType(p, TokenTypVar))
{
if ( IsOfType( p, ID_DBLDOTS ) ) // method for a class
{
2012-08-11 18:59:35 +00:00
func->m_MasterClass = pp->GetString();
2012-08-08 20:35:17 +00:00
CBotClass* pClass = CBotClass::Find(pp);
2015-08-16 10:43:42 +00:00
if ( pClass == nullptr )
2012-08-08 20:35:17 +00:00
{
pStk->SetError(TX_NOCLASS, 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
2015-08-16 10:43:42 +00:00
if (( pClass != nullptr || !pStack->CheckCall(pp, func->m_Param)) &&
( pClass == nullptr || !pClass->CheckCall(pp, func->m_Param)) )
2012-08-08 20:35:17 +00:00
{
if (IsOfType(p, ID_OPBLK))
{
int level = 1;
// and skips the following instruction block
do
{
2012-08-11 18:59:35 +00:00
int type = p->GetType();
p = p->GetNext();
2012-08-08 20:35:17 +00:00
if (type == ID_OPBLK) level++;
if (type == ID_CLBLK) level--;
}
2015-08-16 10:43:42 +00:00
while (level > 0 && p != nullptr);
2012-08-08 20:35:17 +00:00
return pStack->ReturnFunc(func, pStk);
}
pStk->SetError(TX_OPENBLK, p);
}
}
pStk->SetError(TX_REDEF, pp);
}
2012-08-08 00:01:06 +00:00
bad:
2012-08-08 20:35:17 +00:00
pStk->SetError(TX_NOFONC, p);
}
pStk->SetError(TX_NOTYP, p);
delete func;
2015-08-16 10:43:42 +00:00
return pStack->ReturnFunc(nullptr, pStk);
2012-08-08 00:01:06 +00:00
}
2012-08-08 20:35:17 +00:00
#ifdef _DEBUG
2012-08-08 00:01:06 +00:00
static int xx = 0;
#endif
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
bool CBotFunction::Execute(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance)
{
2012-08-08 20:35:17 +00:00
CBotStack* pile = pj->AddStack(this, 2); // one end of stack local to this function
// if ( pile == EOX ) return true;
pile->SetBotCall(m_pProg); // bases for routines
2012-08-11 18:59:35 +00:00
if ( pile->GetState() == 0 )
2012-08-08 20:35:17 +00:00
{
if ( !m_Param->Execute(ppVars, pile) ) return false; // define parameters
pile->IncState();
}
2012-08-11 18:59:35 +00:00
if ( pile->GetState() == 1 && !m_MasterClass.IsEmpty() )
2012-08-08 20:35:17 +00:00
{
// makes "this" known
CBotVar* pThis = nullptr;
2015-08-16 10:43:42 +00:00
if ( pInstance == nullptr )
2012-08-08 20:35:17 +00:00
{
pThis = CBotVar::Create("this", CBotTypResult( CBotTypClass, m_MasterClass ));
}
else
{
pThis = CBotVar::Create("this", CBotTypResult( CBotTypPointer, m_MasterClass ));
pThis->SetPointer(pInstance);
}
assert(pThis);
pThis->SetInit(CBotVar::InitType::IS_POINTER);
2012-08-08 20:35:17 +00:00
// pThis->SetUniqNum(m_nThisIdent);
pThis->SetUniqNum(-2);
pile->AddVar(pThis);
pile->IncState();
}
if ( pile->IfStep() ) return false;
if ( !m_Block->Execute(pile) )
{
2012-08-11 18:59:35 +00:00
if ( pile->GetError() < 0 )
2012-08-08 20:35:17 +00:00
pile->SetError( 0 );
else
return false;
}
return pj->Return(pile);
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
void CBotFunction::RestoreState(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance)
{
2012-08-08 20:35:17 +00:00
CBotStack* pile = pj->RestoreStack(this); // one end of stack local to this function
2015-08-16 10:43:42 +00:00
if ( pile == nullptr ) return;
2012-08-08 20:35:17 +00:00
CBotStack* pile2 = pile;
pile->SetBotCall(m_pProg); // bases for routines
2012-08-11 18:59:35 +00:00
if ( pile->GetBlock() < 2 )
2012-08-08 20:35:17 +00:00
{
2015-08-16 10:43:42 +00:00
CBotStack* pile2 = pile->RestoreStack(nullptr); // one end of stack local to this function
if ( pile2 == nullptr ) return;
2012-08-11 18:59:35 +00:00
pile->SetState(pile->GetState() + pile2->GetState());
2012-08-08 20:35:17 +00:00
pile2->Delete();
}
m_Param->RestoreState(pile2, true); // parameters
if ( !m_MasterClass.IsEmpty() )
{
CBotVar* pThis = pile->FindVar("this");
pThis->SetInit(CBotVar::InitType::IS_POINTER);
2012-08-08 20:35:17 +00:00
pThis->SetUniqNum(-2);
}
m_Block->RestoreState(pile2, true);
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
void CBotFunction::AddNext(CBotFunction* p)
{
2012-08-08 20:35:17 +00:00
CBotFunction* pp = this;
2015-08-16 10:43:42 +00:00
while (pp->m_next != nullptr) pp = pp->m_next;
2012-08-08 00:01:06 +00:00
2012-08-08 20:35:17 +00:00
pp->m_next = p;
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
CBotTypResult CBotFunction::CompileCall(const char* name, CBotVar** ppVars, long& nIdent)
{
2012-08-08 20:35:17 +00:00
nIdent = 0;
CBotTypResult type;
2012-08-08 00:01:06 +00:00
// CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type);
FindLocalOrPublic(nIdent, name, ppVars, type);
2012-08-08 20:35:17 +00:00
return type;
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const char* name, CBotVar** ppVars, CBotTypResult& TypeOrError, bool bPublic)
{
2012-08-08 20:35:17 +00:00
TypeOrError.SetType(TX_UNDEFCALL); // no routine of the name
CBotFunction* pt;
if ( nIdent )
{
2015-08-16 10:43:42 +00:00
if ( this != nullptr ) for ( pt = this ; pt != nullptr ; pt = pt->m_next )
2012-08-08 20:35:17 +00:00
{
if ( pt->m_nFuncIdent == nIdent )
{
TypeOrError = pt->m_retTyp;
return pt;
}
}
// search the list of public functions
2015-08-16 10:43:42 +00:00
for ( pt = m_listPublic ; pt != nullptr ; pt = pt->m_nextpublic )
2012-08-08 20:35:17 +00:00
{
if ( pt->m_nFuncIdent == nIdent )
{
TypeOrError = pt->m_retTyp;
return pt;
}
}
}
2015-08-16 10:43:42 +00:00
if ( name == nullptr ) return nullptr;
2012-08-08 20:35:17 +00:00
int delta = 99999; // seeks the lowest signature
2015-08-16 10:43:42 +00:00
CBotFunction* pFunc = nullptr; // the best function found
2012-08-08 20:35:17 +00:00
2015-08-16 10:43:42 +00:00
if ( this != nullptr )
2012-08-08 20:35:17 +00:00
{
2015-08-16 10:43:42 +00:00
for ( pt = this ; pt != nullptr ; pt = pt->m_next )
2012-08-08 20:35:17 +00:00
{
2012-08-11 18:59:35 +00:00
if ( pt->m_token.GetString() == name )
2012-08-08 20:35:17 +00:00
{
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
2015-08-16 10:43:42 +00:00
while ( pv != nullptr && pw != nullptr)
2012-08-08 20:35:17 +00:00
{
2012-08-11 18:59:35 +00:00
if (!TypesCompatibles(pv->GetTypResult(), pw->GetTypResult()))
2012-08-08 20:35:17 +00:00
{
2015-08-16 10:43:42 +00:00
if ( pFunc == nullptr ) TypeOrError = TX_BADPARAM;
2012-08-08 20:35:17 +00:00
break;
}
2012-08-11 18:59:35 +00:00
int d = pv->GetType() - pw->GetType(2);
2012-08-08 20:35:17 +00:00
alpha += d>0 ? d : -10*d; // quality loss, 10 times more expensive!
2012-08-11 18:59:35 +00:00
pv = pv->GetNext();
2012-08-08 20:35:17 +00:00
pw = ppVars[i++];
}
2015-08-16 10:43:42 +00:00
if ( pw != nullptr )
2012-08-08 20:35:17 +00:00
{
2015-08-16 10:43:42 +00:00
if ( pFunc != nullptr ) continue;
2012-08-08 20:35:17 +00:00
if ( TypeOrError.Eq(TX_LOWPARAM) ) TypeOrError.SetType(TX_NUMPARAM);
if ( TypeOrError.Eq(TX_UNDEFCALL)) TypeOrError.SetType(TX_OVERPARAM);
continue; // too many parameters
}
2015-08-16 10:43:42 +00:00
if ( pv != nullptr )
2012-08-08 20:35:17 +00:00
{
2015-08-16 10:43:42 +00:00
if ( pFunc != nullptr ) continue;
2012-08-08 20:35:17 +00:00
if ( TypeOrError.Eq(TX_OVERPARAM) ) TypeOrError.SetType(TX_NUMPARAM);
if ( TypeOrError.Eq(TX_UNDEFCALL) ) TypeOrError.SetType(TX_LOWPARAM);
continue; // not enough parameters
}
if (alpha == 0) // perfect signature
{
nIdent = pt->m_nFuncIdent;
TypeOrError = pt->m_retTyp;
return pt;
}
if ( alpha < delta ) // a better signature?
{
pFunc = pt;
delta = alpha;
}
}
}
}
if ( bPublic )
{
2015-08-16 10:43:42 +00:00
for ( pt = m_listPublic ; pt != nullptr ; pt = pt->m_nextpublic )
2012-08-08 20:35:17 +00:00
{
2012-08-11 18:59:35 +00:00
if ( pt->m_token.GetString() == name )
2012-08-08 20:35:17 +00:00
{
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
2015-08-16 10:43:42 +00:00
while ( pv != nullptr && pw != nullptr)
2012-08-08 20:35:17 +00:00
{
2012-08-11 18:59:35 +00:00
if (!TypesCompatibles(pv->GetTypResult(), pw->GetTypResult()))
2012-08-08 20:35:17 +00:00
{
2015-08-16 10:43:42 +00:00
if ( pFunc == nullptr ) TypeOrError = TX_BADPARAM;
2012-08-08 20:35:17 +00:00
break;
}
2012-08-11 18:59:35 +00:00
int d = pv->GetType() - pw->GetType(2);
2012-08-08 20:35:17 +00:00
alpha += d>0 ? d : -10*d; // quality loss, 10 times more expensive!
2012-08-11 18:59:35 +00:00
pv = pv->GetNext();
2012-08-08 20:35:17 +00:00
pw = ppVars[i++];
}
2015-08-16 10:43:42 +00:00
if ( pw != nullptr )
2012-08-08 20:35:17 +00:00
{
2015-08-16 10:43:42 +00:00
if ( pFunc != nullptr ) continue;
2012-08-08 20:35:17 +00:00
if ( TypeOrError.Eq(TX_LOWPARAM) ) TypeOrError.SetType(TX_NUMPARAM);
if ( TypeOrError.Eq(TX_UNDEFCALL)) TypeOrError.SetType(TX_OVERPARAM);
continue; // to many parameters
}
2015-08-16 10:43:42 +00:00
if ( pv != nullptr )
2012-08-08 20:35:17 +00:00
{
2015-08-16 10:43:42 +00:00
if ( pFunc != nullptr ) continue;
2012-08-08 20:35:17 +00:00
if ( TypeOrError.Eq(TX_OVERPARAM) ) TypeOrError.SetType(TX_NUMPARAM);
if ( TypeOrError.Eq(TX_UNDEFCALL) ) TypeOrError.SetType(TX_LOWPARAM);
continue; // not enough parameters
}
if (alpha == 0) // perfect signature
{
nIdent = pt->m_nFuncIdent;
TypeOrError = pt->m_retTyp;
return pt;
}
if ( alpha < delta ) // a better signature?
{
pFunc = pt;
delta = alpha;
}
}
}
}
2015-08-16 10:43:42 +00:00
if ( pFunc != nullptr )
2012-08-08 20:35:17 +00:00
{
nIdent = pFunc->m_nFuncIdent;
TypeOrError = pFunc->m_retTyp;
return pFunc;
}
2015-08-16 10:43:42 +00:00
return nullptr;
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
int CBotFunction::DoCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken)
{
2012-08-08 20:35:17 +00:00
CBotTypResult type;
2015-08-16 10:43:42 +00:00
CBotFunction* pt = nullptr;
2012-08-08 20:35:17 +00:00
pt = FindLocalOrPublic(nIdent, name, ppVars, type);
2015-08-16 10:43:42 +00:00
if ( pt != nullptr )
2012-08-08 20:35:17 +00:00
{
CBotStack* pStk1 = pStack->AddStack(pt, 2); // to put "this"
// if ( pStk1 == EOX ) return true;
pStk1->SetBotCall(pt->m_pProg); // it may have changed module
if ( pStk1->IfStep() ) return false;
2015-08-16 10:43:42 +00:00
CBotStack* pStk3 = pStk1->AddStack(nullptr, true); // parameters
2012-08-08 20:35:17 +00:00
// preparing parameters on the stack
2012-08-11 18:59:35 +00:00
if ( pStk1->GetState() == 0 )
2012-08-08 20:35:17 +00:00
{
if ( !pt->m_MasterClass.IsEmpty() )
{
CBotVar* pInstance = m_pProg->m_pInstance;
// make "this" known
CBotVar* pThis ;
2015-08-16 10:43:42 +00:00
if ( pInstance == nullptr )
2012-08-08 20:35:17 +00:00
{
pThis = CBotVar::Create("this", CBotTypResult( CBotTypClass, pt->m_MasterClass ));
}
else
{
pThis = CBotVar::Create("this", CBotTypResult( CBotTypPointer, pt->m_MasterClass ));
pThis->SetPointer(pInstance);
}
assert(pThis);
pThis->SetInit(CBotVar::InitType::IS_POINTER);
2012-08-08 20:35:17 +00:00
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
2012-08-11 18:59:35 +00:00
if ( !pStk3->GetRetVar( // puts the result on the stack
pt->m_Block->Execute(pStk3) )) // GetRetVar said if it is interrupted
2012-08-08 20:35:17 +00:00
{
if ( !pStk3->IsOk() && pt->m_pProg != m_pProg )
{
2012-08-08 00:01:06 +00:00
#ifdef _DEBUG
2012-08-11 18:59:35 +00:00
if ( m_pProg->GetFunctions()->GetName() == "LaCommande" ) return false;
2012-08-08 00:01:06 +00:00
#endif
2012-08-08 20:35:17 +00:00
pStk3->SetPosError(pToken); // indicates the error on the procedure call
}
return false; // interrupt !
}
return pStack->Return( pStk3 );
}
return -1;
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
void CBotFunction::RestoreCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack)
{
2012-08-08 20:35:17 +00:00
CBotTypResult type;
2015-08-16 10:43:42 +00:00
CBotFunction* pt = nullptr;
2012-08-08 20:35:17 +00:00
CBotStack* pStk1;
CBotStack* pStk3;
// search function to return the ok identifier
pt = FindLocalOrPublic(nIdent, name, ppVars, type);
2015-08-16 10:43:42 +00:00
if ( pt != nullptr )
2012-08-08 20:35:17 +00:00
{
pStk1 = pStack->RestoreStack(pt);
2015-08-16 10:43:42 +00:00
if ( pStk1 == nullptr ) return;
2012-08-08 20:35:17 +00:00
pStk1->SetBotCall(pt->m_pProg); // it may have changed module
2012-08-11 18:59:35 +00:00
if ( pStk1->GetBlock() < 2 )
2012-08-08 20:35:17 +00:00
{
2015-08-16 10:43:42 +00:00
CBotStack* pStk2 = pStk1->RestoreStack(nullptr); // used more
if ( pStk2 == nullptr ) return;
pStk3 = pStk2->RestoreStack(nullptr);
if ( pStk3 == nullptr ) return;
2012-08-08 20:35:17 +00:00
}
else
{
2015-08-16 10:43:42 +00:00
pStk3 = pStk1->RestoreStack(nullptr);
if ( pStk3 == nullptr ) return;
2012-08-08 20:35:17 +00:00
}
// preparing parameters on the stack
{
if ( !pt->m_MasterClass.IsEmpty() )
{
// CBotVar* pInstance = m_pProg->m_pInstance;
2012-08-08 20:35:17 +00:00
// make "this" known
CBotVar* pThis = pStk1->FindVar("this");
pThis->SetInit(CBotVar::InitType::IS_POINTER);
2012-08-08 20:35:17 +00:00
pThis->SetUniqNum(-2);
}
}
2012-08-11 18:59:35 +00:00
if ( pStk1->GetState() == 0 )
2012-08-08 20:35:17 +00:00
{
pt->m_Param->RestoreState(pStk3, true);
return;
}
// initializes the variables as parameters
pt->m_Param->RestoreState(pStk3, false);
pt->m_Block->RestoreState(pStk3, true);
}
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
int CBotFunction::DoCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken, CBotClass* pClass)
{
2012-08-08 20:35:17 +00:00
CBotTypResult type;
2012-08-11 18:59:35 +00:00
CBotProgram* pProgCurrent = pStack->GetBotCall();
2012-08-08 20:35:17 +00:00
CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type, false);
2015-08-16 10:43:42 +00:00
if ( pt != nullptr )
2012-08-08 20:35:17 +00:00
{
2012-08-11 18:59:35 +00:00
// DEBUG( "CBotFunction::DoCall" + pt->GetName(), 0, pStack);
2012-08-08 20:35:17 +00:00
CBotStack* pStk = pStack->AddStack(pt, 2);
// if ( pStk == EOX ) return true;
pStk->SetBotCall(pt->m_pProg); // it may have changed module
2015-08-16 10:43:42 +00:00
CBotStack* pStk3 = pStk->AddStack(nullptr, true); // to set parameters passed
2012-08-08 20:35:17 +00:00
// preparing parameters on the stack
2012-08-11 18:59:35 +00:00
if ( pStk->GetState() == 0 )
2012-08-08 20:35:17 +00:00
{
// 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);
2012-08-11 18:59:35 +00:00
CBotClass* pClass = pThis->GetClass()->GetParent();
2012-08-08 20:35:17 +00:00
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();
}
2012-08-11 18:59:35 +00:00
if ( pStk->GetState() == 1 )
2012-08-08 20:35:17 +00:00
{
if ( pt->m_bSynchro )
{
2012-08-11 18:59:35 +00:00
CBotProgram* pProgBase = pStk->GetBotCall(true);
2012-08-08 20:35:17 +00:00
if ( !pClass->Lock(pProgBase) ) return false; // expected to power \TODO attend de pouvoir
}
pStk->IncState();
}
// finally calls the found function
2012-08-11 18:59:35 +00:00
if ( !pStk3->GetRetVar( // puts the result on the stack
pt->m_Block->Execute(pStk3) )) // GetRetVar said if it is interrupted
2012-08-08 20:35:17 +00:00
{
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;
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
void CBotFunction::RestoreCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotClass* pClass)
{
2012-08-08 20:35:17 +00:00
CBotTypResult type;
CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type);
2012-08-08 00:01:06 +00:00
2015-08-16 10:43:42 +00:00
if ( pt != nullptr )
2012-08-08 20:35:17 +00:00
{
CBotStack* pStk = pStack->RestoreStack(pt);
2015-08-16 10:43:42 +00:00
if ( pStk == nullptr ) return;
2012-08-08 20:35:17 +00:00
pStk->SetBotCall(pt->m_pProg); // it may have changed module
2012-08-08 00:01:06 +00:00
2012-08-08 20:35:17 +00:00
CBotVar* pthis = pStk->FindVar("this");
pthis->SetUniqNum(-2);
2012-08-08 00:01:06 +00:00
2015-08-16 10:43:42 +00:00
CBotStack* pStk3 = pStk->RestoreStack(nullptr); // to set parameters passed
if ( pStk3 == nullptr ) return;
2012-08-08 00:01:06 +00:00
2012-08-08 20:35:17 +00:00
pt->m_Param->RestoreState(pStk3, true); // parameters
2012-08-08 00:01:06 +00:00
2012-08-11 18:59:35 +00:00
if ( pStk->GetState() > 1 && // latching is effective?
2012-08-08 20:35:17 +00:00
pt->m_bSynchro )
{
2012-08-11 18:59:35 +00:00
CBotProgram* pProgBase = pStk->GetBotCall(true);
2012-08-08 20:35:17 +00:00
pClass->Lock(pProgBase); // locks the class
}
2012-08-08 00:01:06 +00:00
2012-08-08 20:35:17 +00:00
// finally calls the found function
2012-08-08 00:01:06 +00:00
2012-08-08 20:35:17 +00:00
pt->m_Block->RestoreState(pStk3, true); // interrupt !
}
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
bool CBotFunction::CheckParam(CBotDefParam* pParam)
{
2012-08-08 20:35:17 +00:00
CBotDefParam* pp = m_Param;
2015-08-16 10:43:42 +00:00
while ( pp != nullptr && pParam != nullptr )
2012-08-08 20:35:17 +00:00
{
2012-08-11 18:59:35 +00:00
CBotTypResult type1 = pp->GetType();
CBotTypResult type2 = pParam->GetType();
2012-08-08 20:35:17 +00:00
if ( !type1.Compare(type2) ) return false;
2012-08-11 18:59:35 +00:00
pp = pp->GetNext();
pParam = pParam->GetNext();
2012-08-08 20:35:17 +00:00
}
2015-08-16 10:43:42 +00:00
return ( pp == nullptr && pParam == nullptr );
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-11 18:59:35 +00:00
CBotString CBotFunction::GetName()
2012-08-08 00:01:06 +00:00
{
2012-08-11 18:59:35 +00:00
return m_token.GetString();
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-11 18:59:35 +00:00
CBotString CBotFunction::GetParams()
2012-08-08 00:01:06 +00:00
{
2015-08-16 10:43:42 +00:00
if ( m_Param == nullptr ) return CBotString("()");
2012-08-08 00:01:06 +00:00
2012-08-08 20:35:17 +00:00
CBotString params = "( ";
CBotDefParam* p = m_Param; // list of parameters
2012-08-08 00:01:06 +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
params += p->GetParamString();
p = p->GetNext();
2015-08-16 10:43:42 +00:00
if ( p != nullptr ) params += ", ";
2012-08-08 20:35:17 +00:00
}
2012-08-08 00:01:06 +00:00
2012-08-08 20:35:17 +00:00
params += " )";
return params;
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
CBotFunction* CBotFunction::Next()
{
2012-08-08 20:35:17 +00:00
return m_next;
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
void CBotFunction::AddPublic(CBotFunction* func)
{
2015-08-16 10:43:42 +00:00
if ( m_listPublic != nullptr )
2012-08-08 20:35:17 +00:00
{
func->m_nextpublic = m_listPublic;
m_listPublic->m_prevpublic = func;
}
m_listPublic = func;
2012-08-08 00:01:06 +00:00
}
/////////////////////////////////////////////////////////////////////////
// management of parameters
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
CBotDefParam::CBotDefParam()
{
2015-08-16 10:43:42 +00:00
m_next = nullptr;
2012-08-08 20:35:17 +00:00
m_nIdent = 0;
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
CBotDefParam::~CBotDefParam()
{
2012-08-08 20:35:17 +00:00
delete m_next;
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
// compiles a list of parameters
CBotDefParam* CBotDefParam::Compile(CBotToken* &p, CBotCStack* pStack)
{
2012-08-08 20:35:17 +00:00
// mainly not pStack->TokenStack here
// declared variables must remain visible thereafter
2012-08-11 18:59:35 +00:00
pStack->SetStartError(p->GetStart());
2012-08-08 20:35:17 +00:00
if (IsOfType(p, ID_OPENPAR))
{
2015-08-16 10:43:42 +00:00
CBotDefParam* list = nullptr;
2012-08-08 20:35:17 +00:00
while (!IsOfType(p, ID_CLOSEPAR))
{
CBotDefParam* param = new CBotDefParam();
2015-08-16 10:43:42 +00:00
if (list == nullptr) list = param;
2012-08-08 20:35:17 +00:00
else list->AddNext(param); // added to the list
2015-08-16 10:43:42 +00:00
// CBotClass* pClass = nullptr;//= CBotClass::Find(p);
2012-08-11 18:59:35 +00:00
param->m_typename = p->GetString();
2012-08-08 20:35:17 +00:00
CBotTypResult type = param->m_type = TypeParam(p, pStack);
// if ( type == CBotTypPointer ) type = CBotTypClass; // we must create a new object
2012-08-11 18:59:35 +00:00
if (param->m_type.GetType() > 0)
2012-08-08 20:35:17 +00:00
{
CBotToken* pp = p;
param->m_token = *p;
if (pStack->IsOk() && IsOfType(p, TokenTypVar) )
{
// variable already declared?
if (pStack->CheckVarLocal(pp))
{
pStack->SetError(TX_REDEFVAR, pp);
break;
}
if ( type.Eq(CBotTypArrayPointer) ) type.SetType(CBotTypArrayBody);
2012-08-11 18:59:35 +00:00
CBotVar* var = CBotVar::Create(pp->GetString(), type); // creates the variable
2012-08-08 20:35:17 +00:00
// if ( pClass ) var->SetClass(pClass);
var->SetInit(CBotVar::InitType::IS_POINTER); // mark initialized
2012-08-08 20:35:17 +00:00
param->m_nIdent = CBotVar::NextUniqNum();
var->SetUniqNum(param->m_nIdent);
pStack->AddVar(var); // place on the stack
2012-08-11 18:59:35 +00:00
if (IsOfType(p, ID_COMMA) || p->GetType() == ID_CLOSEPAR)
2012-08-08 20:35:17 +00:00
continue;
}
2012-08-11 18:59:35 +00:00
pStack->SetError(TX_CLOSEPAR, p->GetStart());
2012-08-08 20:35:17 +00:00
}
pStack->SetError(TX_NOTYP, p);
delete list;
2015-08-16 10:43:42 +00:00
return nullptr;
2012-08-08 20:35:17 +00:00
}
return list;
}
2012-08-11 18:59:35 +00:00
pStack->SetError(TX_OPENPAR, p->GetStart());
2015-08-16 10:43:42 +00:00
return nullptr;
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
void CBotDefParam::AddNext(CBotDefParam* p)
{
2012-08-08 20:35:17 +00:00
CBotDefParam* pp = this;
2015-08-16 10:43:42 +00:00
while (pp->m_next != nullptr) pp = pp->m_next;
2012-08-08 00:01:06 +00:00
2012-08-08 20:35:17 +00:00
pp->m_next = p;
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
bool CBotDefParam::Execute(CBotVar** ppVars, CBotStack* &pj)
{
2012-08-08 20:35:17 +00:00
int i = 0;
CBotDefParam* p = this;
2015-08-16 10:43:42 +00:00
while ( p != nullptr )
2012-08-08 20:35:17 +00:00
{
// creates a local variable on the stack
2012-08-11 18:59:35 +00:00
CBotVar* newvar = CBotVar::Create(p->m_token.GetString(), p->m_type);
2012-08-08 20:35:17 +00:00
// serves to make the transformation of types:
2015-08-16 10:43:42 +00:00
if ( ppVars != nullptr && ppVars[i] != nullptr )
2012-08-08 20:35:17 +00:00
{
2012-08-11 18:59:35 +00:00
switch (p->m_type.GetType())
2012-08-08 20:35:17 +00:00
{
case CBotTypInt:
2012-08-11 18:59:35 +00:00
newvar->SetValInt(ppVars[i]->GetValInt());
2012-08-08 20:35:17 +00:00
break;
case CBotTypFloat:
2012-08-11 18:59:35 +00:00
newvar->SetValFloat(ppVars[i]->GetValFloat());
2012-08-08 20:35:17 +00:00
break;
case CBotTypString:
2012-08-11 18:59:35 +00:00
newvar->SetValString(ppVars[i]->GetValString());
2012-08-08 20:35:17 +00:00
break;
case CBotTypBoolean:
2012-08-11 18:59:35 +00:00
newvar->SetValInt(ppVars[i]->GetValInt());
2012-08-08 20:35:17 +00:00
break;
case CBotTypIntrinsic:
(static_cast<CBotVarClass*>(newvar))->Copy(ppVars[i], false);
2012-08-08 20:35:17 +00:00
break;
case CBotTypPointer:
case CBotTypArrayPointer:
{
2012-08-11 18:59:35 +00:00
newvar->SetPointer(ppVars[i]->GetPointer());
2012-08-08 20:35:17 +00:00
}
break;
default:
2013-11-25 19:03:06 +00:00
assert(0);
2012-08-08 20:35:17 +00:00
}
}
newvar->SetUniqNum(p->m_nIdent);
pj->AddVar(newvar); // add a variable
p = p->m_next;
i++;
}
return true;
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
void CBotDefParam::RestoreState(CBotStack* &pj, bool bMain)
{
// int i = 0;
2012-08-08 20:35:17 +00:00
CBotDefParam* p = this;
2015-08-16 10:43:42 +00:00
while ( p != nullptr )
2012-08-08 20:35:17 +00:00
{
// creates a local variable on the stack
2012-08-11 18:59:35 +00:00
CBotVar* var = pj->FindVar(p->m_token.GetString());
2012-08-08 20:35:17 +00:00
var->SetUniqNum(p->m_nIdent);
p = p->m_next;
}
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-11 18:59:35 +00:00
int CBotDefParam::GetType()
2012-08-08 00:01:06 +00:00
{
2012-08-11 18:59:35 +00:00
return m_type.GetType();
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-11 18:59:35 +00:00
CBotTypResult CBotDefParam::GetTypResult()
2012-08-08 00:01:06 +00:00
{
2012-08-08 20:35:17 +00:00
return m_type;
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-11 18:59:35 +00:00
CBotDefParam* CBotDefParam::GetNext()
2012-08-08 00:01:06 +00:00
{
2012-08-08 20:35:17 +00:00
return m_next;
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-11 18:59:35 +00:00
CBotString CBotDefParam::GetParamString()
2012-08-08 00:01:06 +00:00
{
2012-08-08 20:35:17 +00:00
CBotString param;
2012-08-08 20:35:17 +00:00
param = m_typename;
param += ' ';
2012-08-08 00:01:06 +00:00
2012-08-11 18:59:35 +00:00
param += m_token.GetString();
2012-08-08 20:35:17 +00:00
return param;
2012-08-08 00:01:06 +00:00
}
//////////////////////////////////////////////////////////////////////////////
// statement of user classes
// pre-compile a new class
// analysis is complete except the body of routines
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
CBotClass* CBotClass::Compile1(CBotToken* &p, CBotCStack* pStack)
{
2012-08-08 20:35:17 +00:00
if ( !IsOfType(p, ID_PUBLIC) )
{
pStack->SetError(TX_NOPUBLIC, p);
2015-08-16 10:43:42 +00:00
return nullptr;
2012-08-08 20:35:17 +00:00
}
2015-08-16 10:43:42 +00:00
if ( !IsOfType(p, ID_CLASS) ) return nullptr;
2012-08-08 20:35:17 +00:00
2012-08-11 18:59:35 +00:00
CBotString name = p->GetString();
2012-08-08 20:35:17 +00:00
CBotClass* pOld = CBotClass::Find(name);
2015-08-16 10:43:42 +00:00
if ( pOld != nullptr && pOld->m_IsDef )
2012-08-08 20:35:17 +00:00
{
pStack->SetError( TX_REDEFCLASS, p );
2015-08-16 10:43:42 +00:00
return nullptr;
2012-08-08 20:35:17 +00:00
}
// a name of the class is there?
if (IsOfType(p, TokenTypVar))
{
2015-08-16 10:43:42 +00:00
CBotClass* pPapa = nullptr;
2012-08-08 20:35:17 +00:00
if ( IsOfType( p, ID_EXTENDS ) )
{
2012-08-11 18:59:35 +00:00
CBotString name = p->GetString();
2012-08-08 20:35:17 +00:00
pPapa = CBotClass::Find(name);
2015-08-16 10:43:42 +00:00
if (!IsOfType(p, TokenTypVar) || pPapa == nullptr )
2012-08-08 20:35:17 +00:00
{
pStack->SetError( TX_NOCLASS, p );
2015-08-16 10:43:42 +00:00
return nullptr;
2012-08-08 20:35:17 +00:00
}
}
2015-08-16 10:43:42 +00:00
CBotClass* classe = (pOld == nullptr) ? new CBotClass(name, pPapa) : pOld;
2012-08-08 20:35:17 +00:00
classe->Purge(); // emptythe old definitions
classe->m_IsDef = false; // current definition
if ( !IsOfType( p, ID_OPBLK) )
{
pStack->SetError(TX_OPENBLK, p);
2015-08-16 10:43:42 +00:00
return nullptr;
2012-08-08 20:35:17 +00:00
}
while ( pStack->IsOk() && !IsOfType( p, ID_CLBLK ) )
{
classe->CompileDefItem(p, pStack, false);
}
if (pStack->IsOk()) return classe;
}
pStack->SetError(TX_ENDOF, p);
2015-08-16 10:43:42 +00:00
return nullptr;
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
{
2012-08-08 20:35:17 +00:00
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;
2015-08-16 10:43:42 +00:00
// CBotClass* pClass = nullptr;
2012-08-08 20:35:17 +00:00
type = TypeParam(p, pStack); // type of the result
if ( type.Eq(-1) )
{
pStack->SetError(TX_NOTYP, p);
return false;
}
while (pStack->IsOk())
2012-08-08 20:35:17 +00:00
{
CBotToken* pp = p;
IsOfType(p, ID_NOT); // skips ~ eventual (destructor)
if (IsOfType(p, TokenTypVar))
{
2015-08-16 10:43:42 +00:00
CBotInstr* limites = nullptr;
2012-08-08 20:35:17 +00:00
while ( IsOfType( p, ID_OPBRK ) ) // a table?
{
2015-08-16 10:43:42 +00:00
CBotInstr* i = nullptr;
2012-08-08 20:35:17 +00:00
2012-08-11 18:59:35 +00:00
if ( p->GetType() != ID_CLBRK )
2012-08-08 20:35:17 +00:00
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 ) )
{
2012-08-11 18:59:35 +00:00
pStack->SetError(TX_CLBRK, p->GetStart());
2012-08-08 20:35:17 +00:00
return false;
}
2012-08-11 18:59:35 +00:00
/* CBotVar* pv = pStack->GetVar();
if ( pv->GetType()>= CBotTypBoolean )
2012-08-08 20:35:17 +00:00
{
2012-08-11 18:59:35 +00:00
pStack->SetError(TX_BADTYPE, p->GetStart());
2012-08-08 20:35:17 +00:00
return false;
}*/
2015-08-16 10:43:42 +00:00
if (limites == nullptr) limites = i;
2012-08-08 20:35:17 +00:00
else limites->AddNext3(i);
}
2012-08-11 18:59:35 +00:00
if ( p->GetType() == ID_OPENPAR )
2012-08-08 20:35:17 +00:00
{
if ( !bSecond )
{
p = pBase;
CBotFunction* f =
2012-08-08 20:35:17 +00:00
CBotFunction::Compile1(p, pStack, this);
2015-08-16 10:43:42 +00:00
if ( f == nullptr ) return false;
2012-08-08 20:35:17 +00:00
2015-08-16 10:43:42 +00:00
if (m_pMethod == nullptr) m_pMethod = f;
2012-08-08 20:35:17 +00:00
else m_pMethod->AddNext(f);
}
else
{
// return a method precompiled in pass 1
CBotFunction* pf = m_pMethod;
2015-08-16 10:43:42 +00:00
CBotFunction* prev = nullptr;
while ( pf != nullptr )
2012-08-08 20:35:17 +00:00
{
2012-08-11 18:59:35 +00:00
if (pf->GetName() == pp->GetString()) break;
2012-08-08 20:35:17 +00:00
prev = pf;
pf = pf->Next();
}
2012-08-11 18:59:35 +00:00
bool bConstructor = (pp->GetString() == GetName());
2015-08-16 10:43:42 +00:00
CBotCStack* pile = pStack->TokenStack(nullptr, true);
2012-08-08 20:35:17 +00:00
// 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;
2015-08-16 10:43:42 +00:00
while (my != nullptr)
2012-08-08 20:35:17 +00:00
{
// places a copy of variables of a class (this) on a stack
CBotVar* pv = my->m_pVar;
2015-08-16 10:43:42 +00:00
while (pv != nullptr)
2012-08-08 20:35:17 +00:00
{
CBotVar* pcopy = CBotVar::Create(pv);
CBotVar::InitType initType = CBotVar::InitType::UNDEF;
if (!bConstructor || pv->IsStatic())
initType = CBotVar::InitType::DEF;
pcopy->SetInit(initType);
2012-08-11 18:59:35 +00:00
pcopy->SetUniqNum(pv->GetUniqNum());
2012-08-08 20:35:17 +00:00
pile->AddVar(pcopy);
2012-08-11 18:59:35 +00:00
pv = pv->GetNext();
2012-08-08 20:35:17 +00:00
}
my = my->m_pParent;
}
// compiles a method
p = pBase;
CBotFunction* f =
2015-08-16 10:43:42 +00:00
CBotFunction::Compile(p, pile, nullptr/*, false*/);
2012-08-08 20:35:17 +00:00
2015-08-16 10:43:42 +00:00
if ( f != nullptr )
2012-08-08 20:35:17 +00:00
{
2012-08-11 18:59:35 +00:00
f->m_pProg = pStack->GetBotCall();
2012-08-08 20:35:17 +00:00
f->m_bSynchro = bSynchro;
// replaces the element in the chain
f->m_next = pf->m_next;
2015-08-16 10:43:42 +00:00
pf->m_next = nullptr;
2012-08-08 20:35:17 +00:00
delete pf;
2015-08-16 10:43:42 +00:00
if (prev == nullptr) m_pMethod = f;
2012-08-08 20:35:17 +00:00
else prev->m_next = f;
}
2015-08-16 10:43:42 +00:00
pStack->Return(nullptr, pile);
2012-08-08 20:35:17 +00:00
}
return pStack->IsOk();
}
// definition of an element
if (type.Eq(0))
{
pStack->SetError(TX_ENDOF, p);
return false;
}
2015-08-16 10:43:42 +00:00
CBotInstr* i = nullptr;
2012-08-08 20:35:17 +00:00
if ( IsOfType(p, ID_ASS ) )
{
if ( type.Eq(CBotTypArrayPointer) )
{
2012-08-11 18:59:35 +00:00
i = CBotListArray::Compile(p, pStack, type.GetTypElem());
2012-08-08 20:35:17 +00:00
}
else
{
// it has an assignmet to calculate
i = CBotTwoOpExpr::Compile(p, pStack);
}
if ( !pStack->IsOk() ) return false;
}
if ( !bSecond )
{
2012-08-11 18:59:35 +00:00
CBotVar* pv = CBotVar::Create(pp->GetString(), type);
2012-08-08 20:35:17 +00:00
pv -> SetStatic( bStatic );
pv -> SetPrivate( mProtect );
AddItem( pv );
pv->m_InitExpr = i;
pv->m_LimExpr = limites;
2015-08-16 10:43:42 +00:00
if ( pv->IsStatic() && pv->m_InitExpr != nullptr )
2012-08-08 20:35:17 +00:00
{
CBotStack* pile = CBotStack::FirstStack(); // independent stack
while(pile->IsOk() && !pv->m_InitExpr->Execute(pile)); // evaluates the expression without timer
2012-08-11 18:59:35 +00:00
pv->SetVal( pile->GetVar() ) ;
2012-08-08 20:35:17 +00:00
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();
2012-08-08 00:01:06 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 00:01:06 +00:00
CBotClass* CBotClass::Compile(CBotToken* &p, CBotCStack* pStack)
{
2015-08-16 10:43:42 +00:00
if ( !IsOfType(p, ID_PUBLIC) ) return nullptr;
if ( !IsOfType(p, ID_CLASS) ) return nullptr;
2012-08-08 20:35:17 +00:00
2012-08-11 18:59:35 +00:00
CBotString name = p->GetString();
2012-08-08 20:35:17 +00:00
// 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;
}
2012-08-08 20:35:17 +00:00
}
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);
2015-08-16 10:43:42 +00:00
return nullptr;
2012-08-08 00:01:06 +00:00
}