Syntax sugar: Accessing members of returned objects (#808)
Conflicts: src/CBot/CBotInstr/CBotInstrMethode.hdev-new-models
commit
b9d4d57e33
|
@ -0,0 +1,206 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the Colobot: Gold Edition source code
|
||||||
|
* Copyright (C) 2001-2016, 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include "CBot/CBotInstr/CBotExprRetVar.h"
|
||||||
|
|
||||||
|
#include "CBot/CBotInstr/CBotExpression.h"
|
||||||
|
#include "CBot/CBotInstr/CBotInstrMethode.h"
|
||||||
|
#include "CBot/CBotInstr/CBotIndexExpr.h"
|
||||||
|
#include "CBot/CBotInstr/CBotFieldExpr.h"
|
||||||
|
|
||||||
|
#include "CBot/CBotStack.h"
|
||||||
|
|
||||||
|
namespace CBot
|
||||||
|
{
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
CBotExprRetVar::CBotExprRetVar()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
CBotExprRetVar::~CBotExprRetVar()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
CBotInstr* CBotExprRetVar::Compile(CBotToken*& p, CBotCStack* pStack)
|
||||||
|
{
|
||||||
|
if (p->GetType() == ID_DOT)
|
||||||
|
{
|
||||||
|
CBotVar* var = pStack->GetVar();
|
||||||
|
|
||||||
|
if (var == nullptr)
|
||||||
|
{
|
||||||
|
pStack->SetError(CBotErrNoTerminator, p->GetStart());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
CBotCStack* pStk = pStack->TokenStack();
|
||||||
|
CBotInstr* inst = new CBotExprRetVar();
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
pStk->SetStartError(p->GetStart());
|
||||||
|
if (var->GetType() == CBotTypArrayPointer)
|
||||||
|
{
|
||||||
|
if (IsOfType( p, ID_OPBRK ))
|
||||||
|
{
|
||||||
|
CBotIndexExpr* i = new CBotIndexExpr();
|
||||||
|
i->m_expr = CBotExpression::Compile(p, pStk);
|
||||||
|
inst->AddNext3(i);
|
||||||
|
|
||||||
|
var = var->GetItem(0,true);
|
||||||
|
|
||||||
|
if (i->m_expr == nullptr || pStk->GetType() != CBotTypInt)
|
||||||
|
{
|
||||||
|
pStk->SetError(CBotErrBadIndex, p->GetStart());
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
if (!pStk->IsOk() || !IsOfType( p, ID_CLBRK ))
|
||||||
|
{
|
||||||
|
pStk->SetError(CBotErrCloseIndex, p->GetStart());
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (var->GetType(CBotVar::GetTypeMode::CLASS_AS_POINTER) == CBotTypPointer)
|
||||||
|
{
|
||||||
|
if (IsOfType(p, ID_DOT))
|
||||||
|
{
|
||||||
|
CBotToken* pp = p;
|
||||||
|
|
||||||
|
if (p->GetType() == TokenTypVar)
|
||||||
|
{
|
||||||
|
if (p->GetNext()->GetType() == ID_OPENPAR)
|
||||||
|
{
|
||||||
|
CBotInstr* i = CBotInstrMethode::Compile(p, pStk, var);
|
||||||
|
if (!pStk->IsOk()) goto err;
|
||||||
|
inst->AddNext3(i);
|
||||||
|
return pStack->Return(inst, pStk);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CBotFieldExpr* i = new CBotFieldExpr();
|
||||||
|
i->SetToken(pp);
|
||||||
|
inst->AddNext3(i);
|
||||||
|
var = var->GetItem(p->GetString());
|
||||||
|
if (var != nullptr)
|
||||||
|
{
|
||||||
|
i->SetUniqNum(var->GetUniqNum());
|
||||||
|
if ( var->IsPrivate() &&
|
||||||
|
!pStk->GetProgram()->m_bCompileClass)
|
||||||
|
{
|
||||||
|
pStk->SetError(CBotErrPrivate, pp);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (var != nullptr)
|
||||||
|
{
|
||||||
|
p = p->GetNext();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pStk->SetError(CBotErrUndefItem, p);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
pStk->SetError(CBotErrUndefClass, p);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pStk->SetCopyVar(var);
|
||||||
|
if (pStk->IsOk()) return pStack->Return(inst, pStk);
|
||||||
|
|
||||||
|
pStk->SetError(CBotErrUndefVar, p);
|
||||||
|
err:
|
||||||
|
delete inst;
|
||||||
|
return pStack->Return(nullptr, pStk);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool CBotExprRetVar::Execute(CBotStack* &pj)
|
||||||
|
{
|
||||||
|
|
||||||
|
CBotStack* pile = pj->AddStack();
|
||||||
|
CBotStack* pile1 = pile;
|
||||||
|
CBotVar* pVar;
|
||||||
|
|
||||||
|
if (pile1->GetState() == 0)
|
||||||
|
{
|
||||||
|
pVar = pj->GetVar();
|
||||||
|
pVar->Update(pj->GetUserPtr());
|
||||||
|
if (pVar->GetType(CBotVar::GetTypeMode::CLASS_AS_POINTER) == CBotTypNullPointer)
|
||||||
|
{
|
||||||
|
pile1->SetError(CBotErrNull, &m_token);
|
||||||
|
return pj->Return(pile1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !m_next3->ExecuteVar(pVar, pile, &m_token, true, false) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (pVar)
|
||||||
|
pile1->SetCopyVar(pVar);
|
||||||
|
else
|
||||||
|
return pj->Return(pile1);
|
||||||
|
|
||||||
|
pile1->IncState();
|
||||||
|
}
|
||||||
|
pVar = pile1->GetVar();
|
||||||
|
|
||||||
|
if (pVar == nullptr)
|
||||||
|
{
|
||||||
|
return pj->Return(pile1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pVar->IsUndefined())
|
||||||
|
{
|
||||||
|
pile1->SetError(CBotErrNotInit, &m_token);
|
||||||
|
return pj->Return(pile1);
|
||||||
|
}
|
||||||
|
return pj->Return(pile1);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void CBotExprRetVar::RestoreState(CBotStack* &pj, bool bMain)
|
||||||
|
{
|
||||||
|
if (!bMain) return;
|
||||||
|
|
||||||
|
CBotStack* pile = pj->RestoreStack();
|
||||||
|
if ( pile == nullptr ) return;
|
||||||
|
|
||||||
|
if (pile->GetState() == 0)
|
||||||
|
m_next3->RestoreStateVar(pile, bMain);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CBotExprRetVar::GetDebugData()
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << m_token.GetString() << "func(...).something" << std::endl;
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace CBot
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the Colobot: Gold Edition source code
|
||||||
|
* Copyright (C) 2001-2016, 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CBot/CBotInstr/CBotInstr.h"
|
||||||
|
|
||||||
|
namespace CBot
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Access a member/element of the variable on the stack
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class CBotExprRetVar : public CBotInstr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CBotExprRetVar();
|
||||||
|
~CBotExprRetVar();
|
||||||
|
|
||||||
|
static CBotInstr* Compile(CBotToken*& p, CBotCStack* pStack);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Execute
|
||||||
|
* \param pj
|
||||||
|
* \return
|
||||||
|
*/
|
||||||
|
bool Execute(CBotStack* &pj) override;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief RestoreState
|
||||||
|
* \param pj
|
||||||
|
* \param bMain
|
||||||
|
*/
|
||||||
|
void RestoreState(CBotStack* &pj, bool bMain) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual const std::string GetDebugName() override { return "CBotExprRetVar"; }
|
||||||
|
virtual std::string GetDebugData() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace CBot
|
|
@ -69,6 +69,7 @@ private:
|
||||||
CBotInstr* m_expr;
|
CBotInstr* m_expr;
|
||||||
friend class CBotLeftExpr;
|
friend class CBotLeftExpr;
|
||||||
friend class CBotExprVar;
|
friend class CBotExprVar;
|
||||||
|
friend class CBotExprRetVar;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace CBot
|
} // namespace CBot
|
||||||
|
|
|
@ -18,7 +18,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "CBot/CBotInstr/CBotInstrCall.h"
|
#include "CBot/CBotInstr/CBotInstrCall.h"
|
||||||
#include "CBot/CBotInstr/CBotExpression.h"
|
#include "CBot/CBotInstr/CBotExprRetVar.h"
|
||||||
|
#include "CBot/CBotInstr/CBotInstrUtils.h"
|
||||||
|
|
||||||
#include "CBot/CBotStack.h"
|
#include "CBot/CBotStack.h"
|
||||||
|
|
||||||
|
@ -47,62 +48,26 @@ CBotInstrCall::~CBotInstrCall()
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
CBotInstr* CBotInstrCall::Compile(CBotToken* &p, CBotCStack* pStack)
|
CBotInstr* CBotInstrCall::Compile(CBotToken* &p, CBotCStack* pStack)
|
||||||
{
|
{
|
||||||
CBotVar* ppVars[1000];
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
CBotToken* pp = p;
|
CBotToken* pp = p;
|
||||||
p = p->GetNext();
|
p = p->GetNext();
|
||||||
|
|
||||||
pStack->SetStartError(p->GetStart());
|
if (p->GetType() == ID_OPENPAR)
|
||||||
CBotCStack* pile = pStack;
|
|
||||||
|
|
||||||
if ( IsOfType(p, ID_OPENPAR) )
|
|
||||||
{
|
{
|
||||||
int start, end;
|
|
||||||
|
CBotVar* ppVars[1000];
|
||||||
|
|
||||||
CBotInstrCall* inst = new CBotInstrCall();
|
CBotInstrCall* inst = new CBotInstrCall();
|
||||||
inst->SetToken(pp);
|
inst->SetToken(pp);
|
||||||
|
|
||||||
// compile la list of parameters
|
// compile la list of parameters
|
||||||
if (!IsOfType(p, ID_CLOSEPAR)) while (true)
|
inst->m_parameters = CompileParams(p, pStack, ppVars);
|
||||||
{
|
|
||||||
start = p->GetStart();
|
|
||||||
pile = pile->TokenStack(); // keeps the results on the stack
|
|
||||||
|
|
||||||
CBotInstr* param = CBotExpression::Compile(p, pile);
|
if ( !pStack->IsOk() )
|
||||||
end = p->GetStart();
|
|
||||||
if (inst->m_parameters == nullptr ) inst->m_parameters = param;
|
|
||||||
else inst->m_parameters->AddNext(param); // constructs the list
|
|
||||||
|
|
||||||
if ( !pile->IsOk() )
|
|
||||||
{
|
{
|
||||||
delete inst;
|
|
||||||
return pStack->Return(nullptr, pile);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( param != nullptr )
|
|
||||||
{
|
|
||||||
if ( pile->GetTypResult().Eq(99) )
|
|
||||||
{
|
|
||||||
delete pStack->TokenStack();
|
|
||||||
pStack->SetError(CBotErrVoid, p->GetStart());
|
|
||||||
delete inst;
|
delete inst;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
ppVars[i] = pile->GetVar();
|
|
||||||
ppVars[i]->GetToken()->SetPos(start, end);
|
|
||||||
i++;
|
|
||||||
|
|
||||||
if (IsOfType(p, ID_COMMA)) continue; // skips the comma
|
|
||||||
if (IsOfType(p, ID_CLOSEPAR)) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
pStack->SetError(CBotErrClosePar, p->GetStart());
|
|
||||||
delete pStack->TokenStack();
|
|
||||||
delete inst;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
ppVars[i] = nullptr;
|
|
||||||
|
|
||||||
// the routine is known?
|
// the routine is known?
|
||||||
// CBotClass* pClass = nullptr;
|
// CBotClass* pClass = nullptr;
|
||||||
|
@ -124,6 +89,17 @@ CBotInstr* CBotInstrCall::Compile(CBotToken* &p, CBotCStack* pStack)
|
||||||
}
|
}
|
||||||
else pStack->SetVar(nullptr); // routine returns void
|
else pStack->SetVar(nullptr); // routine returns void
|
||||||
|
|
||||||
|
if (nullptr != (inst->m_exprRetVar = CBotExprRetVar::Compile(p, pStack)))
|
||||||
|
{
|
||||||
|
inst->m_exprRetVar->SetToken(&inst->m_token);
|
||||||
|
delete pStack->TokenStack();
|
||||||
|
}
|
||||||
|
if ( !pStack->IsOk() )
|
||||||
|
{
|
||||||
|
delete inst;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
return inst;
|
return inst;
|
||||||
}
|
}
|
||||||
p = pp;
|
p = pp;
|
||||||
|
@ -138,6 +114,17 @@ bool CBotInstrCall::Execute(CBotStack* &pj)
|
||||||
CBotStack* pile = pj->AddStack(this);
|
CBotStack* pile = pj->AddStack(this);
|
||||||
if ( pile->StackOver() ) return pj->Return( pile );
|
if ( pile->StackOver() ) return pj->Return( pile );
|
||||||
|
|
||||||
|
CBotStack* pile3 = nullptr;
|
||||||
|
if (m_exprRetVar != nullptr) // func().member
|
||||||
|
{
|
||||||
|
pile3 = pile->AddStack2();
|
||||||
|
if (pile3->GetState() == 1) // function call is done?
|
||||||
|
{
|
||||||
|
if (!m_exprRetVar->Execute(pile3)) return false;
|
||||||
|
return pj->Return(pile3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// CBotStack* pile1 = pile;
|
// CBotStack* pile1 = pile;
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
@ -165,6 +152,14 @@ bool CBotInstrCall::Execute(CBotStack* &pj)
|
||||||
|
|
||||||
if ( !pile2->ExecuteCall(m_nFuncIdent, GetToken(), ppVars, m_typRes)) return false; // interrupt
|
if ( !pile2->ExecuteCall(m_nFuncIdent, GetToken(), ppVars, m_typRes)) return false; // interrupt
|
||||||
|
|
||||||
|
if (m_exprRetVar != nullptr) // func().member
|
||||||
|
{
|
||||||
|
pile3->SetCopyVar( pile2->GetVar() ); // copy the result
|
||||||
|
pile2->SetVar(nullptr);
|
||||||
|
pile3->SetState(1); // set call is done
|
||||||
|
return false; // go back to the top ^^^
|
||||||
|
}
|
||||||
|
|
||||||
return pj->Return(pile2); // release the entire stack
|
return pj->Return(pile2); // release the entire stack
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,6 +171,16 @@ void CBotInstrCall::RestoreState(CBotStack* &pj, bool bMain)
|
||||||
CBotStack* pile = pj->RestoreStack(this);
|
CBotStack* pile = pj->RestoreStack(this);
|
||||||
if ( pile == nullptr ) return;
|
if ( pile == nullptr ) return;
|
||||||
|
|
||||||
|
if (m_exprRetVar != nullptr) // func().member
|
||||||
|
{
|
||||||
|
CBotStack* pile3 = pile->AddStack2();
|
||||||
|
if (pile3->GetState() == 1) // function call is done?
|
||||||
|
{
|
||||||
|
m_exprRetVar->RestoreState(pile3, bMain);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// CBotStack* pile1 = pile;
|
// CBotStack* pile1 = pile;
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
|
@ -69,6 +69,10 @@ private:
|
||||||
CBotTypResult m_typRes;
|
CBotTypResult m_typRes;
|
||||||
//! Id of a function.
|
//! Id of a function.
|
||||||
long m_nFuncIdent;
|
long m_nFuncIdent;
|
||||||
|
|
||||||
|
//! Instruction to return a member of the returned object.
|
||||||
|
CBotInstr* m_exprRetVar;
|
||||||
|
|
||||||
friend class CBotDebug;
|
friend class CBotDebug;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include "CBot/CBotInstr/CBotInstrMethode.h"
|
#include "CBot/CBotInstr/CBotInstrMethode.h"
|
||||||
|
|
||||||
|
#include "CBot/CBotInstr/CBotExprRetVar.h"
|
||||||
#include "CBot/CBotInstr/CBotInstrUtils.h"
|
#include "CBot/CBotInstr/CBotInstrUtils.h"
|
||||||
|
|
||||||
#include "CBot/CBotStack.h"
|
#include "CBot/CBotStack.h"
|
||||||
|
@ -87,6 +88,15 @@ CBotInstr* CBotInstrMethode::Compile(CBotToken* &p, CBotCStack* pStack, CBotVar*
|
||||||
}
|
}
|
||||||
pStack->SetVar(pResult);
|
pStack->SetVar(pResult);
|
||||||
}
|
}
|
||||||
|
else pStack->SetVar(nullptr);
|
||||||
|
|
||||||
|
if (nullptr != (inst->m_exprRetVar = CBotExprRetVar::Compile(p, pStack)))
|
||||||
|
{
|
||||||
|
inst->m_exprRetVar->SetToken(&inst->m_token);
|
||||||
|
delete pStack->TokenStack();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( pStack->IsOk() )
|
||||||
return inst;
|
return inst;
|
||||||
}
|
}
|
||||||
delete inst;
|
delete inst;
|
||||||
|
@ -107,6 +117,18 @@ bool CBotInstrMethode::ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* pre
|
||||||
return pj->Return(pile1);
|
return pj->Return(pile1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CBotStack* pile3 = nullptr;
|
||||||
|
if (m_exprRetVar != nullptr) // .func().member
|
||||||
|
{
|
||||||
|
pile3 = pile1->AddStack2();
|
||||||
|
if (pile3->GetState() == 1)
|
||||||
|
{
|
||||||
|
if (!m_exprRetVar->Execute(pile3)) return false;
|
||||||
|
pVar = nullptr;
|
||||||
|
return pj->Return(pile3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (pile1->IfStep()) return false;
|
if (pile1->IfStep()) return false;
|
||||||
|
|
||||||
CBotStack* pile2 = pile1->AddStack(); // for the next parameters
|
CBotStack* pile2 = pile1->AddStack(); // for the next parameters
|
||||||
|
@ -166,6 +188,15 @@ bool CBotInstrMethode::ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* pre
|
||||||
pResult, pile2, GetToken())) return false;
|
pResult, pile2, GetToken())) return false;
|
||||||
if (pRes != pResult) delete pRes;
|
if (pRes != pResult) delete pRes;
|
||||||
|
|
||||||
|
if (m_exprRetVar != nullptr) // .func().member
|
||||||
|
{
|
||||||
|
pile3->SetCopyVar( pile2->GetVar() );
|
||||||
|
pile2->SetVar(nullptr);
|
||||||
|
pile3->SetState(1); // set call is done
|
||||||
|
pVar = nullptr;
|
||||||
|
return false; // go back to the top ^^^
|
||||||
|
}
|
||||||
|
|
||||||
pVar = nullptr; // does not return value for this
|
pVar = nullptr; // does not return value for this
|
||||||
return pj->Return(pile2); // release the entire stack
|
return pj->Return(pile2); // release the entire stack
|
||||||
}
|
}
|
||||||
|
@ -179,6 +210,16 @@ void CBotInstrMethode::RestoreStateVar(CBotStack* &pile, bool bMain)
|
||||||
CBotStack* pile1 = pile->RestoreStack(this); // place for the copy of This
|
CBotStack* pile1 = pile->RestoreStack(this); // place for the copy of This
|
||||||
if (pile1 == nullptr) return;
|
if (pile1 == nullptr) return;
|
||||||
|
|
||||||
|
if (m_exprRetVar != nullptr) // .func().member
|
||||||
|
{
|
||||||
|
CBotStack* pile3 = pile1->AddStack2();
|
||||||
|
if (pile3->GetState() == 1) // function call is done?
|
||||||
|
{
|
||||||
|
m_exprRetVar->RestoreState(pile3, bMain);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CBotStack* pile2 = pile1->RestoreStack(); // and for the parameters coming
|
CBotStack* pile2 = pile1->RestoreStack(); // and for the parameters coming
|
||||||
if (pile2 == nullptr) return;
|
if (pile2 == nullptr) return;
|
||||||
|
|
||||||
|
|
|
@ -86,6 +86,9 @@ private:
|
||||||
//! Variable ID
|
//! Variable ID
|
||||||
long m_thisIdent;
|
long m_thisIdent;
|
||||||
|
|
||||||
|
//! Instruction to return a member of the returned object.
|
||||||
|
CBotInstr* m_exprRetVar;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace CBot
|
} // namespace CBot
|
||||||
|
|
|
@ -54,6 +54,8 @@ set(SOURCES
|
||||||
CBotInstr/CBotExprLitNum.h
|
CBotInstr/CBotExprLitNum.h
|
||||||
CBotInstr/CBotExprLitString.cpp
|
CBotInstr/CBotExprLitString.cpp
|
||||||
CBotInstr/CBotExprLitString.h
|
CBotInstr/CBotExprLitString.h
|
||||||
|
CBotInstr/CBotExprRetVar.cpp
|
||||||
|
CBotInstr/CBotExprRetVar.h
|
||||||
CBotInstr/CBotExprUnaire.cpp
|
CBotInstr/CBotExprUnaire.cpp
|
||||||
CBotInstr/CBotExprUnaire.h
|
CBotInstr/CBotExprUnaire.h
|
||||||
CBotInstr/CBotExprVar.cpp
|
CBotInstr/CBotExprVar.cpp
|
||||||
|
|
|
@ -1465,3 +1465,254 @@ TEST_F(CBotUT, AccessMembersInParameters_Issue256)
|
||||||
"}\n"
|
"}\n"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(CBotUT, InstrCallAccessMemberVoid)
|
||||||
|
{
|
||||||
|
ExecuteTest(
|
||||||
|
"void Test() {}\n"
|
||||||
|
"extern void TestAccessMemberVoid() {\n"
|
||||||
|
" Test().x;\n"
|
||||||
|
"}\n",
|
||||||
|
CBotErrNoTerminator
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CBotUT, InstrCallAccessMemberNonObject)
|
||||||
|
{
|
||||||
|
ExecuteTest(
|
||||||
|
"int GetInt() {\n"
|
||||||
|
" return 1;\n"
|
||||||
|
"}\n"
|
||||||
|
"extern void TestAccessMemberNonObject() {\n"
|
||||||
|
" GetInt().x;\n"
|
||||||
|
"}\n",
|
||||||
|
CBotErrNoTerminator
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CBotUT, InstrCallAccessMemberObjectNull)
|
||||||
|
{
|
||||||
|
ExecuteTest(
|
||||||
|
"public class TestClass { int x = 1; }\n"
|
||||||
|
"TestClass GetObjectNull() {\n"
|
||||||
|
" TestClass t = null;"
|
||||||
|
" return t;\n"
|
||||||
|
"}\n"
|
||||||
|
"extern void TestAccessMemberObjectNull() {\n"
|
||||||
|
" GetObjectNull().x;\n"
|
||||||
|
"}\n",
|
||||||
|
CBotErrNull
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CBotUT, InstrCallAccessMemberReturnNull)
|
||||||
|
{
|
||||||
|
ExecuteTest(
|
||||||
|
"public class TestClass { int x = 1; }\n"
|
||||||
|
"TestClass GetReturnNull() {\n"
|
||||||
|
" return null;\n"
|
||||||
|
"}\n"
|
||||||
|
"extern void TestAccessMemberReturnNull() {\n"
|
||||||
|
" GetReturnNull().x;\n"
|
||||||
|
"}\n",
|
||||||
|
CBotErrNull
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CBotUT, InstrCallAccessMemberNotVar)
|
||||||
|
{
|
||||||
|
ExecuteTest(
|
||||||
|
"public class TestClass {}\n"
|
||||||
|
"TestClass GetObject(TestClass t) {\n"
|
||||||
|
" return t;\n"
|
||||||
|
"}\n"
|
||||||
|
"extern void TestAccessMemberNotVar() {\n"
|
||||||
|
" TestClass tc();\n"
|
||||||
|
" GetObject(tc).123;\n"
|
||||||
|
"}\n",
|
||||||
|
CBotErrUndefClass
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CBotUT, InstrCallAccessMemberVarNonMember)
|
||||||
|
{
|
||||||
|
ExecuteTest(
|
||||||
|
"public class TestClass { int x = 1; }\n"
|
||||||
|
"TestClass GetObject(TestClass t) {\n"
|
||||||
|
" return t;\n"
|
||||||
|
"}\n"
|
||||||
|
"extern void TestAccessMemberVarNonMember() {\n"
|
||||||
|
" TestClass tc();\n"
|
||||||
|
" GetObject(tc).y;\n"
|
||||||
|
"}\n",
|
||||||
|
CBotErrUndefItem
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CBotUT, InstrCallAccessMemberVarUndefined)
|
||||||
|
{
|
||||||
|
ExecuteTest(
|
||||||
|
"public class TestClass { int x; }\n"
|
||||||
|
"TestClass GetObject(TestClass t) {\n"
|
||||||
|
" return t;\n"
|
||||||
|
"}\n"
|
||||||
|
"extern void TestAccessMemberVarUndefined() {\n"
|
||||||
|
" TestClass tc();\n"
|
||||||
|
" GetObject(tc).x;\n"
|
||||||
|
"}\n",
|
||||||
|
CBotErrNotInit
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CBotUT, InstrCallAccessMemberVarPrivate)
|
||||||
|
{
|
||||||
|
ExecuteTest(
|
||||||
|
"public class TestClass { private int x = 123; }\n"
|
||||||
|
"TestClass GetObject(TestClass t) {\n"
|
||||||
|
" return t;\n"
|
||||||
|
"}\n"
|
||||||
|
"extern void TestAccessMemberVarPrivate() {\n"
|
||||||
|
" TestClass tc();\n"
|
||||||
|
" ASSERT(123 == GetObject(tc).x);\n"
|
||||||
|
"}\n",
|
||||||
|
CBotErrPrivate
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CBotUT, InstrCallAccessMemberVar)
|
||||||
|
{
|
||||||
|
ExecuteTest(
|
||||||
|
"public class TestClass { int x = 123; }\n"
|
||||||
|
"TestClass GetObject(TestClass t) {\n"
|
||||||
|
" return t;\n"
|
||||||
|
"}\n"
|
||||||
|
"extern void TestAccessMemberVar() {\n"
|
||||||
|
" TestClass tc();\n"
|
||||||
|
" ASSERT(123 == GetObject(tc).x);\n"
|
||||||
|
"}\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CBotUT, InstrCallAccessMemberVarArrayBadIndex)
|
||||||
|
{
|
||||||
|
ExecuteTest(
|
||||||
|
"public class TestClass { int[] a; }\n"
|
||||||
|
"TestClass GetObject(TestClass t) {\n"
|
||||||
|
" return t;\n"
|
||||||
|
"}\n"
|
||||||
|
"extern void TestAccessMemberVarArrayEmpty() {\n"
|
||||||
|
" TestClass tc();\n"
|
||||||
|
" int i = GetObject(tc).a[4.7];\n"
|
||||||
|
"}\n",
|
||||||
|
CBotErrBadIndex
|
||||||
|
);
|
||||||
|
}
|
||||||
|
TEST_F(CBotUT, InstrCallAccessMemberVarArrayCloseIndex)
|
||||||
|
{
|
||||||
|
ExecuteTest(
|
||||||
|
"public class TestClass { int[] a = {123}; }\n"
|
||||||
|
"TestClass GetObject(TestClass t) {\n"
|
||||||
|
" return t;\n"
|
||||||
|
"}\n"
|
||||||
|
"extern void TestAccessMemberVarArrayEmpty() {\n"
|
||||||
|
" TestClass tc();\n"
|
||||||
|
" int i = GetObject(tc).a[0;\n"
|
||||||
|
"}\n",
|
||||||
|
CBotErrCloseIndex
|
||||||
|
);
|
||||||
|
}
|
||||||
|
TEST_F(CBotUT, InstrCallAccessMemberVarArrayEmpty)
|
||||||
|
{
|
||||||
|
ExecuteTest(
|
||||||
|
"public class TestClass { int[] a; }\n"
|
||||||
|
"TestClass GetObject(TestClass t) {\n"
|
||||||
|
" return t;\n"
|
||||||
|
"}\n"
|
||||||
|
"extern void TestAccessMemberVarArrayEmpty() {\n"
|
||||||
|
" TestClass tc();\n"
|
||||||
|
" int i = GetObject(tc).a[0];\n"
|
||||||
|
"}\n",
|
||||||
|
CBotErrOutArray
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CBotUT, InstrCallAccessMemberVarArrayOutOfRange)
|
||||||
|
{
|
||||||
|
ExecuteTest(
|
||||||
|
"public class TestClass { int a[] = {123}; }\n"
|
||||||
|
"TestClass GetObject(TestClass t) {\n"
|
||||||
|
" return t;\n"
|
||||||
|
"}\n"
|
||||||
|
"extern void TestAccessMemberVarArrayOut() {\n"
|
||||||
|
" TestClass tc();\n"
|
||||||
|
" int i = GetObject(tc).a[1];\n"
|
||||||
|
"}\n",
|
||||||
|
CBotErrOutArray
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CBotUT, InstrCallAccessMemberVarArray)
|
||||||
|
{
|
||||||
|
ExecuteTest(
|
||||||
|
"public class TestClass { int a[] = {123}; }\n"
|
||||||
|
"TestClass GetObject(TestClass t) {\n"
|
||||||
|
" return t;\n"
|
||||||
|
"}\n"
|
||||||
|
"extern void TestAccessMemberVarArray() {\n"
|
||||||
|
" TestClass tc();\n"
|
||||||
|
" ASSERT(123 == GetObject(tc).a[0]);\n"
|
||||||
|
"}\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CBotUT, InstrCallAccessMemberMethod)
|
||||||
|
{
|
||||||
|
ExecuteTest(
|
||||||
|
"public class TestClass {\n"
|
||||||
|
" int x = 123;\n"
|
||||||
|
" int testGetX() { return x; }\n"
|
||||||
|
"}\n"
|
||||||
|
"TestClass GetObject(TestClass t) {\n"
|
||||||
|
" return t;\n"
|
||||||
|
"}\n"
|
||||||
|
"extern void TestAccessMemberMethod() {\n"
|
||||||
|
" TestClass tc();\n"
|
||||||
|
" ASSERT(123 == GetObject(tc).testGetX());\n"
|
||||||
|
"}\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CBotUT, InstrCallAccessMemberMethodChain)
|
||||||
|
{
|
||||||
|
ExecuteTest(
|
||||||
|
"public class TestClass {\n"
|
||||||
|
" int x = 123;\n"
|
||||||
|
" TestClass testGetThis() { return this; }\n"
|
||||||
|
" int testGetX() { return x; }\n"
|
||||||
|
"}\n"
|
||||||
|
"TestClass GetObject(TestClass t) {\n"
|
||||||
|
" return t;\n"
|
||||||
|
"}\n"
|
||||||
|
"extern void TestAccessMemberMethodChain() {\n"
|
||||||
|
" TestClass tc();\n"
|
||||||
|
" ASSERT(123 == GetObject(tc).testGetThis().testGetX());\n"
|
||||||
|
"}\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CBotUT, InstrCallAccessMemberNewObjectDestructor)
|
||||||
|
{
|
||||||
|
ExecuteTest(
|
||||||
|
"public class TestClass {\n"
|
||||||
|
" int x = 123;\n"
|
||||||
|
" static bool b = false;\n"
|
||||||
|
" void ~TestClass() { b = true; }\n"
|
||||||
|
"}\n"
|
||||||
|
"TestClass GetNewObject() { return new TestClass(); }\n"
|
||||||
|
"extern void TestAccessMemberNewObject() {\n"
|
||||||
|
" TestClass tc();\n"
|
||||||
|
" ASSERT(123 == GetNewObject().x);\n"
|
||||||
|
" ASSERT(tc.b == true);\n"
|
||||||
|
"}\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue