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;
|
||||
friend class CBotLeftExpr;
|
||||
friend class CBotExprVar;
|
||||
friend class CBotExprRetVar;
|
||||
};
|
||||
|
||||
} // namespace CBot
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
*/
|
||||
|
||||
#include "CBot/CBotInstr/CBotInstrCall.h"
|
||||
#include "CBot/CBotInstr/CBotExpression.h"
|
||||
#include "CBot/CBotInstr/CBotExprRetVar.h"
|
||||
#include "CBot/CBotInstr/CBotInstrUtils.h"
|
||||
|
||||
#include "CBot/CBotStack.h"
|
||||
|
||||
|
@ -47,62 +48,26 @@ CBotInstrCall::~CBotInstrCall()
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
CBotInstr* CBotInstrCall::Compile(CBotToken* &p, CBotCStack* pStack)
|
||||
{
|
||||
CBotVar* ppVars[1000];
|
||||
|
||||
int i = 0;
|
||||
|
||||
CBotToken* pp = p;
|
||||
p = p->GetNext();
|
||||
|
||||
pStack->SetStartError(p->GetStart());
|
||||
CBotCStack* pile = pStack;
|
||||
|
||||
if ( IsOfType(p, ID_OPENPAR) )
|
||||
if (p->GetType() == ID_OPENPAR)
|
||||
{
|
||||
int start, end;
|
||||
|
||||
CBotVar* ppVars[1000];
|
||||
|
||||
CBotInstrCall* inst = new CBotInstrCall();
|
||||
inst->SetToken(pp);
|
||||
|
||||
// compile la list of parameters
|
||||
if (!IsOfType(p, ID_CLOSEPAR)) while (true)
|
||||
{
|
||||
start = p->GetStart();
|
||||
pile = pile->TokenStack(); // keeps the results on the stack
|
||||
inst->m_parameters = CompileParams(p, pStack, ppVars);
|
||||
|
||||
CBotInstr* param = CBotExpression::Compile(p, pile);
|
||||
end = p->GetStart();
|
||||
if (inst->m_parameters == nullptr ) inst->m_parameters = param;
|
||||
else inst->m_parameters->AddNext(param); // constructs the list
|
||||
|
||||
if ( !pile->IsOk() )
|
||||
if ( !pStack->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;
|
||||
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?
|
||||
// CBotClass* pClass = nullptr;
|
||||
|
@ -124,6 +89,17 @@ CBotInstr* CBotInstrCall::Compile(CBotToken* &p, CBotCStack* pStack)
|
|||
}
|
||||
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;
|
||||
}
|
||||
p = pp;
|
||||
|
@ -138,6 +114,17 @@ bool CBotInstrCall::Execute(CBotStack* &pj)
|
|||
CBotStack* pile = pj->AddStack(this);
|
||||
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;
|
||||
|
||||
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 (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
|
||||
}
|
||||
|
||||
|
@ -176,6 +171,16 @@ void CBotInstrCall::RestoreState(CBotStack* &pj, bool bMain)
|
|||
CBotStack* pile = pj->RestoreStack(this);
|
||||
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;
|
||||
|
||||
int i = 0;
|
||||
|
|
|
@ -69,6 +69,10 @@ private:
|
|||
CBotTypResult m_typRes;
|
||||
//! Id of a function.
|
||||
long m_nFuncIdent;
|
||||
|
||||
//! Instruction to return a member of the returned object.
|
||||
CBotInstr* m_exprRetVar;
|
||||
|
||||
friend class CBotDebug;
|
||||
};
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <sstream>
|
||||
#include "CBot/CBotInstr/CBotInstrMethode.h"
|
||||
|
||||
#include "CBot/CBotInstr/CBotExprRetVar.h"
|
||||
#include "CBot/CBotInstr/CBotInstrUtils.h"
|
||||
|
||||
#include "CBot/CBotStack.h"
|
||||
|
@ -87,6 +88,15 @@ CBotInstr* CBotInstrMethode::Compile(CBotToken* &p, CBotCStack* pStack, CBotVar*
|
|||
}
|
||||
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;
|
||||
}
|
||||
delete inst;
|
||||
|
@ -107,6 +117,18 @@ bool CBotInstrMethode::ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* pre
|
|||
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;
|
||||
|
||||
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;
|
||||
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
|
||||
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
|
||||
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
|
||||
if (pile2 == nullptr) return;
|
||||
|
||||
|
|
|
@ -86,6 +86,9 @@ private:
|
|||
//! Variable ID
|
||||
long m_thisIdent;
|
||||
|
||||
//! Instruction to return a member of the returned object.
|
||||
CBotInstr* m_exprRetVar;
|
||||
|
||||
};
|
||||
|
||||
} // namespace CBot
|
||||
|
|
|
@ -54,6 +54,8 @@ set(SOURCES
|
|||
CBotInstr/CBotExprLitNum.h
|
||||
CBotInstr/CBotExprLitString.cpp
|
||||
CBotInstr/CBotExprLitString.h
|
||||
CBotInstr/CBotExprRetVar.cpp
|
||||
CBotInstr/CBotExprRetVar.h
|
||||
CBotInstr/CBotExprUnaire.cpp
|
||||
CBotInstr/CBotExprUnaire.h
|
||||
CBotInstr/CBotExprVar.cpp
|
||||
|
|
|
@ -1465,3 +1465,254 @@ TEST_F(CBotUT, AccessMembersInParameters_Issue256)
|
|||
"}\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