1440 lines
46 KiB
C++
1440 lines
46 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 "CBotFunction.h"
|
||
![]() |
|
||
|
#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
|
||
![]() |
#include <cassert>
|
||
|
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
CBotFunction::CBotFunction()
|
||
|
{
|
||
![]() |
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
|
||
![]() |
m_bExtern = false; // function not extern
|
||
![]() |
m_nextpublic = nullptr;
|
||
|
m_prevpublic = nullptr;
|
||
|
m_pProg = nullptr;
|
||
![]() |
// m_nThisIdent = 0;
|
||
|
m_nFuncIdent = 0;
|
||
|
m_bSynchro = false;
|
||
![]() |
}
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
CBotFunction* CBotFunction::m_listPublic = nullptr;
|
||
![]() |
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
CBotFunction::~CBotFunction()
|
||
|
{
|
||
![]() |
delete m_Param; // empty parameter list
|
||
|
delete m_Block; // the instruction block
|
||
|
delete m_next;
|
||
|
|
||
|
// remove public list if there is
|
||
|
if ( m_bPublic )
|
||
|
{
|
||
![]() |
if ( m_nextpublic != nullptr )
|
||
![]() |
{
|
||
|
m_nextpublic->m_prevpublic = m_prevpublic;
|
||
|
}
|
||
![]() |
if ( m_prevpublic != nullptr)
|
||
![]() |
{
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
![]() |
}
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
bool CBotFunction::IsPublic()
|
||
|
{
|
||
![]() |
return m_bPublic;
|
||
![]() |
}
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
bool CBotFunction::IsExtern()
|
||
|
{
|
||
![]() |
return m_bExtern;
|
||
![]() |
}
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
bool CBotFunction::GetPosition(int& start, int& stop, CBotGet modestart, CBotGet modestop)
|
||
|
{
|
||
![]() |
start = m_extern.GetStart();
|
||
|
stop = m_closeblk.GetEnd();
|
||
![]() |
|
||
|
if (modestart == GetPosExtern)
|
||
|
{
|
||
![]() |
start = m_extern.GetStart();
|
||
![]() |
}
|
||
|
if (modestop == GetPosExtern)
|
||
|
{
|
||
![]() |
stop = m_extern.GetEnd();
|
||
![]() |
}
|
||
|
if (modestart == GetPosNom)
|
||
|
{
|
||
![]() |
start = m_token.GetStart();
|
||
![]() |
}
|
||
|
if (modestop == GetPosNom)
|
||
|
{
|
||
![]() |
stop = m_token.GetEnd();
|
||
![]() |
}
|
||
|
if (modestart == GetPosParam)
|
||
|
{
|
||
![]() |
start = m_openpar.GetStart();
|
||
![]() |
}
|
||
|
if (modestop == GetPosParam)
|
||
|
{
|
||
![]() |
stop = m_closepar.GetEnd();
|
||
![]() |
}
|
||
|
if (modestart == GetPosBloc)
|
||
|
{
|
||
![]() |
start = m_openblk.GetStart();
|
||
![]() |
}
|
||
|
if (modestop == GetPosBloc)
|
||
|
{
|
||
![]() |
stop = m_closeblk.GetEnd();
|
||
![]() |
}
|
||
|
|
||
|
return true;
|
||
![]() |
}
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
CBotTypResult ArrayType(CBotToken* &p, CBotCStack* pile, CBotTypResult type)
|
||
![]() |
{
|
||
![]() |
while ( IsOfType( p, ID_OPBRK ) )
|
||
|
{
|
||
|
if ( !IsOfType( p, ID_CLBRK ) )
|
||
|
{
|
||
![]() |
pile->SetError(TX_CLBRK, p->GetStart());
|
||
![]() |
return CBotTypResult( -1 );
|
||
|
}
|
||
|
type = CBotTypResult( CBotTypArrayPointer, type );
|
||
|
}
|
||
|
return type;
|
||
![]() |
}
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
CBotTypResult TypeParam(CBotToken* &p, CBotCStack* pile)
|
||
![]() |
{
|
||
![]() |
CBotClass* pClass = nullptr;
|
||
![]() |
|
||
![]() |
switch (p->GetType())
|
||
![]() |
{
|
||
|
case ID_INT:
|
||
![]() |
p = p->GetNext();
|
||
![]() |
return ArrayType(p, pile, CBotTypResult( CBotTypInt ));
|
||
|
case ID_FLOAT:
|
||
![]() |
p = p->GetNext();
|
||
![]() |
return ArrayType(p, pile, CBotTypResult( CBotTypFloat ));
|
||
|
case ID_BOOLEAN:
|
||
|
case ID_BOOL:
|
||
![]() |
p = p->GetNext();
|
||
![]() |
return ArrayType(p, pile, CBotTypResult( CBotTypBoolean ));
|
||
|
case ID_STRING:
|
||
![]() |
p = p->GetNext();
|
||
![]() |
return ArrayType(p, pile, CBotTypResult( CBotTypString ));
|
||
|
case ID_VOID:
|
||
![]() |
p = p->GetNext();
|
||
![]() |
return CBotTypResult( 0 );
|
||
|
|
||
|
case TokenTypVar:
|
||
|
pClass = CBotClass::Find(p);
|
||
![]() |
if ( pClass != nullptr)
|
||
![]() |
{
|
||
![]() |
p = p->GetNext();
|
||
![]() |
return ArrayType(p, pile,
|
||
|
pClass->IsIntrinsic() ?
|
||
|
CBotTypResult( CBotTypIntrinsic, pClass ) :
|
||
![]() |
CBotTypResult( CBotTypPointer, pClass ) );
|
||
|
}
|
||
|
}
|
||
|
return CBotTypResult( -1 );
|
||
![]() |
}
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
CBotFunction* CBotFunction::Compile(CBotToken* &p, CBotCStack* pStack, CBotFunction* finput, bool bLocal)
|
||
|
{
|
||
![]() |
CBotToken* pp;
|
||
|
CBotFunction* func = finput;
|
||
![]() |
if ( func == nullptr ) func = new CBotFunction();
|
||
![]() |
|
||
|
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
|
||
|
|
||
![]() |
if (func->m_retTyp.GetType() >= 0)
|
||
![]() |
{
|
||
|
CBotToken* pp = p;
|
||
|
func->m_token = *p;
|
||
|
|
||
|
if ( IsOfType(p, ID_NOT) )
|
||
|
{
|
||
![]() |
CBotToken d(CBotString("~") + p->GetString());
|
||
![]() |
func->m_token = d;
|
||
|
}
|
||
|
|
||
|
// un nom de fonction est-il là ?
|
||
|
if (IsOfType(p, TokenTypVar))
|
||
|
{
|
||
|
if ( IsOfType( p, ID_DBLDOTS ) ) // method for a class
|
||
|
{
|
||
![]() |
func->m_MasterClass = pp->GetString();
|
||
![]() |
CBotClass* pClass = CBotClass::Find(pp);
|
||
![]() |
if ( pClass == nullptr ) goto bad;
|
||
![]() |
|
||
|
// pp = p;
|
||
|
func->m_token = *p;
|
||
|
if (!IsOfType(p, TokenTypVar)) goto bad;
|
||
|
|
||
|
}
|
||
|
func->m_openpar = p;
|
||
|
func->m_Param = CBotDefParam::Compile( p, pStk );
|
||
![]() |
func->m_closepar = p->GetPrev();
|
||
![]() |
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);
|
||
![]() |
// 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
|
||
![]() |
CBotVar* pv = pThis->GetItemList();
|
||
![]() |
// int num = 1;
|
||
![]() |
while (pv != nullptr)
|
||
![]() |
{
|
||
|
CBotVar* pcopy = CBotVar::Create(pv);
|
||
|
// pcopy->SetInit(2);
|
||
|
pcopy->Copy(pv);
|
||
![]() |
pcopy->SetPrivate(pv->GetPrivate());
|
||
|
// pcopy->SetUniqNum(pv->GetUniqNum()); //num++);
|
||
![]() |
pStk->AddVar(pcopy);
|
||
![]() |
pv = pv->GetNext();
|
||
![]() |
}
|
||
|
}
|
||
|
|
||
![]() |
// and compiles the following instruction block
|
||
![]() |
func->m_openblk = p;
|
||
|
func->m_Block = CBotBlock::Compile(p, pStk, false);
|
||
![]() |
func->m_closeblk = p->GetPrev();
|
||
![]() |
if ( pStk->IsOk() )
|
||
|
{
|
||
|
if ( func->m_bPublic ) // public function, return known for all
|
||
|
{
|
||
|
CBotFunction::AddPublic(func);
|
||
|
}
|
||
|
return pStack->ReturnFunc(func, pStk);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
![]() |
bad:
|
||
![]() |
pStk->SetError(TX_NOFONC, p);
|
||
|
}
|
||
|
pStk->SetError(TX_NOTYP, p);
|
||
![]() |
if ( finput == nullptr ) delete func;
|
||
|
return pStack->ReturnFunc(nullptr, pStk);
|
||
![]() |
}
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
CBotFunction* CBotFunction::Compile1(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass)
|
||
![]() |
{
|
||
![]() |
CBotFunction* func = new CBotFunction();
|
||
|
func->m_nFuncIdent = CBotVar::NextUniqNum();
|
||
![]() |
|
||
![]() |
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
|
||
|
|
||
![]() |
if (func->m_retTyp.GetType() >= 0)
|
||
![]() |
{
|
||
|
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
|
||
|
{
|
||
![]() |
func->m_MasterClass = pp->GetString();
|
||
![]() |
CBotClass* pClass = CBotClass::Find(pp);
|
||
![]() |
if ( pClass == nullptr )
|
||
![]() |
{
|
||
|
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
|
||
![]() |
if (( pClass != nullptr || !pStack->CheckCall(pp, func->m_Param)) &&
|
||
|
( pClass == nullptr || !pClass->CheckCall(pp, func->m_Param)) )
|
||
![]() |
{
|
||
|
if (IsOfType(p, ID_OPBLK))
|
||
|
{
|
||
|
int level = 1;
|
||
|
// and skips the following instruction block
|
||
|
do
|
||
|
{
|
||
![]() |
int type = p->GetType();
|
||
|
p = p->GetNext();
|
||
![]() |
if (type == ID_OPBLK) level++;
|
||
|
if (type == ID_CLBLK) level--;
|
||
|
}
|
||
![]() |
while (level > 0 && p != nullptr);
|
||
![]() |
|
||
![]() |
return pStack->ReturnFunc(func, pStk);
|
||
|
}
|
||
|
pStk->SetError(TX_OPENBLK, p);
|
||
|
}
|
||
|
}
|
||
|
pStk->SetError(TX_REDEF, pp);
|
||
|
}
|
||
![]() |
bad:
|
||
![]() |
pStk->SetError(TX_NOFONC, p);
|
||
|
}
|
||
|
pStk->SetError(TX_NOTYP, p);
|
||
|
delete func;
|
||
![]() |
return pStack->ReturnFunc(nullptr, pStk);
|
||
![]() |
}
|
||
|
|
||
![]() |
#ifdef _DEBUG
|
||
![]() |
static int xx = 0;
|
||
|
#endif
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
bool CBotFunction::Execute(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance)
|
||
|
{
|
||
![]() |
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
|
||
|
|
||
![]() |
if ( pile->GetState() == 0 )
|
||
![]() |
{
|
||
|
if ( !m_Param->Execute(ppVars, pile) ) return false; // define parameters
|
||
|
pile->IncState();
|
||
|
}
|
||
|
|
||
![]() |
if ( pile->GetState() == 1 && !m_MasterClass.IsEmpty() )
|
||
![]() |
{
|
||
|
// makes "this" known
|
||
![]() |
CBotVar* pThis = nullptr;
|
||
![]() |
if ( pInstance == nullptr )
|
||
![]() |
{
|
||
|
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);
|
||
![]() |
|
||
|
// pThis->SetUniqNum(m_nThisIdent);
|
||
|
pThis->SetUniqNum(-2);
|
||
|
pile->AddVar(pThis);
|
||
|
|
||
|
pile->IncState();
|
||
|
}
|
||
|
|
||
|
if ( pile->IfStep() ) return false;
|
||
|
|
||
|
if ( !m_Block->Execute(pile) )
|
||
|
{
|
||
![]() |
if ( pile->GetError() < 0 )
|
||
![]() |
pile->SetError( 0 );
|
||
|
else
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return pj->Return(pile);
|
||
![]() |
}
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
void CBotFunction::RestoreState(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance)
|
||
|
{
|
||
![]() |
CBotStack* pile = pj->RestoreStack(this); // one end of stack local to this function
|
||
![]() |
if ( pile == nullptr ) return;
|
||
![]() |
CBotStack* pile2 = pile;
|
||
|
|
||
|
pile->SetBotCall(m_pProg); // bases for routines
|
||
|
|
||
![]() |
if ( pile->GetBlock() < 2 )
|
||
![]() |
{
|
||
![]() |
CBotStack* pile2 = pile->RestoreStack(nullptr); // one end of stack local to this function
|
||
|
if ( pile2 == nullptr ) return;
|
||
![]() |
pile->SetState(pile->GetState() + pile2->GetState());
|
||
![]() |
pile2->Delete();
|
||
|
}
|
||
|
|
||
|
m_Param->RestoreState(pile2, true); // parameters
|
||
|
|
||
|
if ( !m_MasterClass.IsEmpty() )
|
||
|
{
|
||
|
CBotVar* pThis = pile->FindVar("this");
|
||
![]() |
pThis->SetInit(CBotVar::InitType::IS_POINTER);
|
||
![]() |
pThis->SetUniqNum(-2);
|
||
|
}
|
||
|
|
||
|
m_Block->RestoreState(pile2, true);
|
||
![]() |
}
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
void CBotFunction::AddNext(CBotFunction* p)
|
||
|
{
|
||
![]() |
CBotFunction* pp = this;
|
||
![]() |
while (pp->m_next != nullptr) pp = pp->m_next;
|
||
![]() |
|
||
![]() |
pp->m_next = p;
|
||
![]() |
}
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
CBotTypResult CBotFunction::CompileCall(const char* name, CBotVar** ppVars, long& nIdent)
|
||
|
{
|
||
![]() |
nIdent = 0;
|
||
|
CBotTypResult type;
|
||
![]() |
|
||
![]() |
// CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type);
|
||
|
FindLocalOrPublic(nIdent, name, ppVars, type);
|
||
![]() |
return type;
|
||
![]() |
}
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const char* name, CBotVar** ppVars, CBotTypResult& TypeOrError, bool bPublic)
|
||
|
{
|
||
![]() |
TypeOrError.SetType(TX_UNDEFCALL); // no routine of the name
|
||
|
CBotFunction* pt;
|
||
|
|
||
|
if ( nIdent )
|
||
|
{
|
||
![]() |
if ( this != nullptr ) for ( pt = this ; pt != nullptr ; pt = pt->m_next )
|
||
![]() |
{
|
||
|
if ( pt->m_nFuncIdent == nIdent )
|
||
|
{
|
||
|
TypeOrError = pt->m_retTyp;
|
||
|
return pt;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// search the list of public functions
|
||
|
|
||
![]() |
for ( pt = m_listPublic ; pt != nullptr ; pt = pt->m_nextpublic )
|
||
![]() |
{
|
||
|
if ( pt->m_nFuncIdent == nIdent )
|
||
|
{
|
||
|
TypeOrError = pt->m_retTyp;
|
||
|
return pt;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
![]() |
if ( name == nullptr ) return nullptr;
|
||
![]() |
|
||
|
int delta = 99999; // seeks the lowest signature
|
||
![]() |
CBotFunction* pFunc = nullptr; // the best function found
|
||
![]() |
|
||
![]() |
if ( this != nullptr )
|
||
![]() |
{
|
||
![]() |
for ( pt = this ; pt != nullptr ; pt = pt->m_next )
|
||
![]() |
{
|
||
![]() |
if ( pt->m_token.GetString() == name )
|
||
![]() |
{
|
||
|
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
|
||
![]() |
while ( pv != nullptr && pw != nullptr)
|
||
![]() |
{
|
||
![]() |
if (!TypesCompatibles(pv->GetTypResult(), pw->GetTypResult()))
|
||
![]() |
{
|
||
![]() |
if ( pFunc == nullptr ) TypeOrError = TX_BADPARAM;
|
||
![]() |
break;
|
||
|
}
|
||
![]() |
int d = pv->GetType() - pw->GetType(2);
|
||
![]() |
alpha += d>0 ? d : -10*d; // quality loss, 10 times more expensive!
|
||
|
|
||
![]() |
pv = pv->GetNext();
|
||
![]() |
pw = ppVars[i++];
|
||
|
}
|
||
![]() |
if ( pw != nullptr )
|
||
![]() |
{
|
||
![]() |
if ( pFunc != nullptr ) continue;
|
||
![]() |
if ( TypeOrError.Eq(TX_LOWPARAM) ) TypeOrError.SetType(TX_NUMPARAM);
|
||
|
if ( TypeOrError.Eq(TX_UNDEFCALL)) TypeOrError.SetType(TX_OVERPARAM);
|
||
|
continue; // too many parameters
|
||
|
}
|
||
![]() |
if ( pv != nullptr )
|
||
![]() |
{
|
||
![]() |
if ( pFunc != nullptr ) continue;
|
||
![]() |
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 )
|
||
|
{
|
||
![]() |
for ( pt = m_listPublic ; pt != nullptr ; pt = pt->m_nextpublic )
|
||
![]() |
{
|
||
![]() |
if ( pt->m_token.GetString() == name )
|
||
![]() |
{
|
||
|
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
|
||
![]() |
while ( pv != nullptr && pw != nullptr)
|
||
![]() |
{
|
||
![]() |
if (!TypesCompatibles(pv->GetTypResult(), pw->GetTypResult()))
|
||
![]() |
{
|
||
![]() |
if ( pFunc == nullptr ) TypeOrError = TX_BADPARAM;
|
||
![]() |
break;
|
||
|
}
|
||
![]() |
int d = pv->GetType() - pw->GetType(2);
|
||
![]() |
alpha += d>0 ? d : -10*d; // quality loss, 10 times more expensive!
|
||
|
|
||
![]() |
pv = pv->GetNext();
|
||
![]() |
pw = ppVars[i++];
|
||
|
}
|
||
![]() |
if ( pw != nullptr )
|
||
![]() |
{
|
||
![]() |
if ( pFunc != nullptr ) continue;
|
||
![]() |
if ( TypeOrError.Eq(TX_LOWPARAM) ) TypeOrError.SetType(TX_NUMPARAM);
|
||
|
if ( TypeOrError.Eq(TX_UNDEFCALL)) TypeOrError.SetType(TX_OVERPARAM);
|
||
|
continue; // to many parameters
|
||
|
}
|
||
![]() |
if ( pv != nullptr )
|
||
![]() |
{
|
||
![]() |
if ( pFunc != nullptr ) continue;
|
||
![]() |
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 ( pFunc != nullptr )
|
||
![]() |
{
|
||
|
nIdent = pFunc->m_nFuncIdent;
|
||
|
TypeOrError = pFunc->m_retTyp;
|
||
|
return pFunc;
|
||
|
}
|
||
![]() |
return nullptr;
|
||
![]() |
}
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
int CBotFunction::DoCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken)
|
||
|
{
|
||
![]() |
CBotTypResult type;
|
||
![]() |
CBotFunction* pt = nullptr;
|
||
![]() |
|
||
![]() |
pt = FindLocalOrPublic(nIdent, name, ppVars, type);
|
||
|
|
||
![]() |
if ( pt != nullptr )
|
||
![]() |
{
|
||
|
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;
|
||
|
|
||
![]() |
CBotStack* pStk3 = pStk1->AddStack(nullptr, true); // parameters
|
||
![]() |
|
||
|
// preparing parameters on the stack
|
||
|
|
||
![]() |
if ( pStk1->GetState() == 0 )
|
||
![]() |
{
|
||
|
if ( !pt->m_MasterClass.IsEmpty() )
|
||
|
{
|
||
|
CBotVar* pInstance = m_pProg->m_pInstance;
|
||
|
// make "this" known
|
||
|
CBotVar* pThis ;
|
||
![]() |
if ( pInstance == nullptr )
|
||
![]() |
{
|
||
|
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);
|
||
![]() |
|
||
|
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
|
||
|
|
||
![]() |
if ( !pStk3->GetRetVar( // puts the result on the stack
|
||
|
pt->m_Block->Execute(pStk3) )) // GetRetVar said if it is interrupted
|
||
![]() |
{
|
||
|
if ( !pStk3->IsOk() && pt->m_pProg != m_pProg )
|
||
|
{
|
||
![]() |
#ifdef _DEBUG
|
||
![]() |
if ( m_pProg->GetFunctions()->GetName() == "LaCommande" ) return false;
|
||
![]() |
#endif
|
||
![]() |
pStk3->SetPosError(pToken); // indicates the error on the procedure call
|
||
|
}
|
||
|
return false; // interrupt !
|
||
|
}
|
||
|
|
||
|
return pStack->Return( pStk3 );
|
||
|
}
|
||
|
return -1;
|
||
![]() |
}
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
void CBotFunction::RestoreCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack)
|
||
|
{
|
||
![]() |
CBotTypResult type;
|
||
![]() |
CBotFunction* pt = nullptr;
|
||
![]() |
CBotStack* pStk1;
|
||
|
CBotStack* pStk3;
|
||
|
|
||
|
// search function to return the ok identifier
|
||
|
|
||
|
pt = FindLocalOrPublic(nIdent, name, ppVars, type);
|
||
|
|
||
![]() |
if ( pt != nullptr )
|
||
![]() |
{
|
||
|
pStk1 = pStack->RestoreStack(pt);
|
||
![]() |
if ( pStk1 == nullptr ) return;
|
||
![]() |
|
||
|
pStk1->SetBotCall(pt->m_pProg); // it may have changed module
|
||
|
|
||
![]() |
if ( pStk1->GetBlock() < 2 )
|
||
![]() |
{
|
||
![]() |
CBotStack* pStk2 = pStk1->RestoreStack(nullptr); // used more
|
||
|
if ( pStk2 == nullptr ) return;
|
||
|
pStk3 = pStk2->RestoreStack(nullptr);
|
||
|
if ( pStk3 == nullptr ) return;
|
||
![]() |
}
|
||
|
else
|
||
|
{
|
||
![]() |
pStk3 = pStk1->RestoreStack(nullptr);
|
||
|
if ( pStk3 == nullptr ) return;
|
||
![]() |
}
|
||
|
|
||
|
// preparing parameters on the stack
|
||
|
|
||
|
{
|
||
|
if ( !pt->m_MasterClass.IsEmpty() )
|
||
|
{
|
||
![]() |
// CBotVar* pInstance = m_pProg->m_pInstance;
|
||
![]() |
// make "this" known
|
||
|
CBotVar* pThis = pStk1->FindVar("this");
|
||
![]() |
pThis->SetInit(CBotVar::InitType::IS_POINTER);
|
||
![]() |
pThis->SetUniqNum(-2);
|
||
|
}
|
||
|
}
|
||
|
|
||
![]() |
if ( pStk1->GetState() == 0 )
|
||
![]() |
{
|
||
|
pt->m_Param->RestoreState(pStk3, true);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// initializes the variables as parameters
|
||
|
pt->m_Param->RestoreState(pStk3, false);
|
||
|
pt->m_Block->RestoreState(pStk3, true);
|
||
|
}
|
||
![]() |
}
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
int CBotFunction::DoCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken, CBotClass* pClass)
|
||
|
{
|
||
![]() |
CBotTypResult type;
|
||
![]() |
CBotProgram* pProgCurrent = pStack->GetBotCall();
|
||
![]() |
|
||
|
CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type, false);
|
||
|
|
||
![]() |
if ( pt != nullptr )
|
||
![]() |
{
|
||
![]() |
// DEBUG( "CBotFunction::DoCall" + pt->GetName(), 0, pStack);
|
||
![]() |
|
||
|
CBotStack* pStk = pStack->AddStack(pt, 2);
|
||
|
// if ( pStk == EOX ) return true;
|
||
|
|
||
|
pStk->SetBotCall(pt->m_pProg); // it may have changed module
|
||
![]() |
CBotStack* pStk3 = pStk->AddStack(nullptr, true); // to set parameters passed
|
||
![]() |
|
||
|
// preparing parameters on the stack
|
||
|
|
||
![]() |
if ( pStk->GetState() == 0 )
|
||
![]() |
{
|
||
|
// 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);
|
||
|
|
||
![]() |
CBotClass* pClass = pThis->GetClass()->GetParent();
|
||
![]() |
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();
|
||
|
}
|
||
|
|
||
![]() |
if ( pStk->GetState() == 1 )
|
||
![]() |
{
|
||
|
if ( pt->m_bSynchro )
|
||
|
{
|
||
![]() |
CBotProgram* pProgBase = pStk->GetBotCall(true);
|
||
![]() |
if ( !pClass->Lock(pProgBase) ) return false; // expected to power \TODO attend de pouvoir
|
||
|
}
|
||
|
pStk->IncState();
|
||
|
}
|
||
|
// finally calls the found function
|
||
|
|
||
![]() |
if ( !pStk3->GetRetVar( // puts the result on the stack
|
||
|
pt->m_Block->Execute(pStk3) )) // GetRetVar said if it is interrupted
|
||
![]() |
{
|
||
|
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;
|
||
![]() |
}
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
void CBotFunction::RestoreCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotClass* pClass)
|
||
|
{
|
||
![]() |
CBotTypResult type;
|
||
|
CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type);
|
||
![]() |
|
||
![]() |
if ( pt != nullptr )
|
||
![]() |
{
|
||
|
CBotStack* pStk = pStack->RestoreStack(pt);
|
||
![]() |
if ( pStk == nullptr ) return;
|
||
![]() |
pStk->SetBotCall(pt->m_pProg); // it may have changed module
|
||
![]() |
|
||
![]() |
CBotVar* pthis = pStk->FindVar("this");
|
||
|
pthis->SetUniqNum(-2);
|
||
![]() |
|
||
![]() |
CBotStack* pStk3 = pStk->RestoreStack(nullptr); // to set parameters passed
|
||
|
if ( pStk3 == nullptr ) return;
|
||
![]() |
|
||
![]() |
pt->m_Param->RestoreState(pStk3, true); // parameters
|
||
![]() |
|
||
![]() |
if ( pStk->GetState() > 1 && // latching is effective?
|
||
![]() |
pt->m_bSynchro )
|
||
|
{
|
||
![]() |
CBotProgram* pProgBase = pStk->GetBotCall(true);
|
||
![]() |
pClass->Lock(pProgBase); // locks the class
|
||
|
}
|
||
![]() |
|
||
![]() |
// finally calls the found function
|
||
![]() |
|
||
![]() |
pt->m_Block->RestoreState(pStk3, true); // interrupt !
|
||
|
}
|
||
![]() |
}
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
bool CBotFunction::CheckParam(CBotDefParam* pParam)
|
||
|
{
|
||
![]() |
CBotDefParam* pp = m_Param;
|
||
![]() |
while ( pp != nullptr && pParam != nullptr )
|
||
![]() |
{
|
||
![]() |
CBotTypResult type1 = pp->GetType();
|
||
|
CBotTypResult type2 = pParam->GetType();
|
||
![]() |
if ( !type1.Compare(type2) ) return false;
|
||
![]() |
pp = pp->GetNext();
|
||
|
pParam = pParam->GetNext();
|
||
![]() |
}
|
||
![]() |
return ( pp == nullptr && pParam == nullptr );
|
||
![]() |
}
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
CBotString CBotFunction::GetName()
|
||
![]() |
{
|
||
![]() |
return m_token.GetString();
|
||
![]() |
}
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
CBotString CBotFunction::GetParams()
|
||
![]() |
{
|
||
![]() |
if ( m_Param == nullptr ) return CBotString("()");
|
||
![]() |
|
||
![]() |
CBotString params = "( ";
|
||
|
CBotDefParam* p = m_Param; // list of parameters
|
||
![]() |
|
||
![]() |
while (p != nullptr)
|
||
![]() |
{
|
||
![]() |
params += p->GetParamString();
|
||
|
p = p->GetNext();
|
||
![]() |
if ( p != nullptr ) params += ", ";
|
||
![]() |
}
|
||
![]() |
|
||
![]() |
params += " )";
|
||
|
return params;
|
||
![]() |
}
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
CBotFunction* CBotFunction::Next()
|
||
|
{
|
||
![]() |
return m_next;
|
||
![]() |
}
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
void CBotFunction::AddPublic(CBotFunction* func)
|
||
|
{
|
||
![]() |
if ( m_listPublic != nullptr )
|
||
![]() |
{
|
||
|
func->m_nextpublic = m_listPublic;
|
||
|
m_listPublic->m_prevpublic = func;
|
||
|
}
|
||
|
m_listPublic = func;
|
||
![]() |
}
|
||
|
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////
|
||
|
// management of parameters
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
CBotDefParam::CBotDefParam()
|
||
|
{
|
||
![]() |
m_next = nullptr;
|
||
![]() |
m_nIdent = 0;
|
||
![]() |
}
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
CBotDefParam::~CBotDefParam()
|
||
|
{
|
||
![]() |
delete m_next;
|
||
![]() |
}
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
// compiles a list of parameters
|
||
|
CBotDefParam* CBotDefParam::Compile(CBotToken* &p, CBotCStack* pStack)
|
||
|
{
|
||
![]() |
// mainly not pStack->TokenStack here
|
||
|
// declared variables must remain visible thereafter
|
||
|
|
||
![]() |
pStack->SetStartError(p->GetStart());
|
||
![]() |
|
||
|
if (IsOfType(p, ID_OPENPAR))
|
||
|
{
|
||
![]() |
CBotDefParam* list = nullptr;
|
||
![]() |
|
||
![]() |
while (!IsOfType(p, ID_CLOSEPAR))
|
||
|
{
|
||
|
CBotDefParam* param = new CBotDefParam();
|
||
![]() |
if (list == nullptr) list = param;
|
||
![]() |
else list->AddNext(param); // added to the list
|
||
|
|
||
![]() |
// CBotClass* pClass = nullptr;//= CBotClass::Find(p);
|
||
![]() |
param->m_typename = p->GetString();
|
||
![]() |
CBotTypResult type = param->m_type = TypeParam(p, pStack);
|
||
|
// if ( type == CBotTypPointer ) type = CBotTypClass; // we must create a new object
|
||
|
|
||
![]() |
if (param->m_type.GetType() > 0)
|
||
![]() |
{
|
||
|
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);
|
||
![]() |
CBotVar* var = CBotVar::Create(pp->GetString(), type); // creates the variable
|
||
![]() |
// if ( pClass ) var->SetClass(pClass);
|
||
![]() |
var->SetInit(CBotVar::InitType::IS_POINTER); // mark initialized
|
||
![]() |
param->m_nIdent = CBotVar::NextUniqNum();
|
||
|
var->SetUniqNum(param->m_nIdent);
|
||
|
pStack->AddVar(var); // place on the stack
|
||
|
|
||
![]() |
if (IsOfType(p, ID_COMMA) || p->GetType() == ID_CLOSEPAR)
|
||
![]() |
continue;
|
||
|
}
|
||
![]() |
pStack->SetError(TX_CLOSEPAR, p->GetStart());
|
||
![]() |
}
|
||
|
pStack->SetError(TX_NOTYP, p);
|
||
|
delete list;
|
||
![]() |
return nullptr;
|
||
![]() |
}
|
||
|
return list;
|
||
|
}
|
||
![]() |
pStack->SetError(TX_OPENPAR, p->GetStart());
|
||
![]() |
return nullptr;
|
||
![]() |
}
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
void CBotDefParam::AddNext(CBotDefParam* p)
|
||
|
{
|
||
![]() |
CBotDefParam* pp = this;
|
||
![]() |
while (pp->m_next != nullptr) pp = pp->m_next;
|
||
![]() |
|
||
![]() |
pp->m_next = p;
|
||
![]() |
}
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
bool CBotDefParam::Execute(CBotVar** ppVars, CBotStack* &pj)
|
||
|
{
|
||
![]() |
int i = 0;
|
||
|
CBotDefParam* p = this;
|
||
|
|
||
![]() |
while ( p != nullptr )
|
||
![]() |
{
|
||
|
// creates a local variable on the stack
|
||
![]() |
CBotVar* newvar = CBotVar::Create(p->m_token.GetString(), p->m_type);
|
||
![]() |
|
||
|
// serves to make the transformation of types:
|
||
![]() |
if ( ppVars != nullptr && ppVars[i] != nullptr )
|
||
![]() |
{
|
||
![]() |
switch (p->m_type.GetType())
|
||
![]() |
{
|
||
|
case CBotTypInt:
|
||
![]() |
newvar->SetValInt(ppVars[i]->GetValInt());
|
||
![]() |
break;
|
||
|
case CBotTypFloat:
|
||
![]() |
newvar->SetValFloat(ppVars[i]->GetValFloat());
|
||
![]() |
break;
|
||
|
case CBotTypString:
|
||
![]() |
newvar->SetValString(ppVars[i]->GetValString());
|
||
![]() |
break;
|
||
|
case CBotTypBoolean:
|
||
![]() |
newvar->SetValInt(ppVars[i]->GetValInt());
|
||
![]() |
break;
|
||
|
case CBotTypIntrinsic:
|
||
![]() |
(static_cast<CBotVarClass*>(newvar))->Copy(ppVars[i], false);
|
||
![]() |
break;
|
||
|
case CBotTypPointer:
|
||
|
case CBotTypArrayPointer:
|
||
|
{
|
||
![]() |
newvar->SetPointer(ppVars[i]->GetPointer());
|
||
![]() |
}
|
||
|
break;
|
||
|
default:
|
||
![]() |
assert(0);
|
||
![]() |
}
|
||
|
}
|
||
|
newvar->SetUniqNum(p->m_nIdent);
|
||
|
pj->AddVar(newvar); // add a variable
|
||
|
p = p->m_next;
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
![]() |
}
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
void CBotDefParam::RestoreState(CBotStack* &pj, bool bMain)
|
||
|
{
|
||
![]() |
// int i = 0;
|
||
![]() |
CBotDefParam* p = this;
|
||
|
|
||
![]() |
while ( p != nullptr )
|
||
![]() |
{
|
||
|
// creates a local variable on the stack
|
||
![]() |
CBotVar* var = pj->FindVar(p->m_token.GetString());
|
||
![]() |
var->SetUniqNum(p->m_nIdent);
|
||
|
p = p->m_next;
|
||
|
}
|
||
![]() |
}
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
int CBotDefParam::GetType()
|
||
![]() |
{
|
||
![]() |
return m_type.GetType();
|
||
![]() |
}
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
CBotTypResult CBotDefParam::GetTypResult()
|
||
![]() |
{
|
||
![]() |
return m_type;
|
||
![]() |
}
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
CBotDefParam* CBotDefParam::GetNext()
|
||
![]() |
{
|
||
![]() |
return m_next;
|
||
![]() |
}
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
CBotString CBotDefParam::GetParamString()
|
||
![]() |
{
|
||
![]() |
CBotString param;
|
||
![]() |
|
||
![]() |
param = m_typename;
|
||
|
param += ' ';
|
||
![]() |
|
||
![]() |
param += m_token.GetString();
|
||
![]() |
return param;
|
||
![]() |
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
// statement of user classes
|
||
|
|
||
|
// pre-compile a new class
|
||
|
// analysis is complete except the body of routines
|
||
|
|
||
![]() |
////////////////////////////////////////////////////////////////////////////////
|
||
![]() |
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;
|
||
![]() |
}
|
||
![]() |
|