Fix increment and decrement syntax

dev-buzzingcars
melex750 2017-01-16 11:38:34 -05:00 committed by krzys_h
parent d7fae300b9
commit 8fc0151444
7 changed files with 83 additions and 35 deletions

View File

@ -44,7 +44,7 @@ CBotExprVar::~CBotExprVar()
}
////////////////////////////////////////////////////////////////////////////////
CBotInstr* CBotExprVar::Compile(CBotToken*& p, CBotCStack* pStack, CBotVar::ProtectionLevel privat)
CBotInstr* CBotExprVar::Compile(CBotToken*& p, CBotCStack* pStack, bool bCheckReadOnly)
{
// CBotToken* pDebut = p;
CBotCStack* pStk = pStack->TokenStack();
@ -67,7 +67,7 @@ CBotInstr* CBotExprVar::Compile(CBotToken*& p, CBotCStack* pStack, CBotVar::Prot
if (ident > 0 && ident < 9000)
{
if (CBotFieldExpr::CheckProtectionError(pStk, nullptr, var, privat))
if (CBotFieldExpr::CheckProtectionError(pStk, nullptr, var, bCheckReadOnly))
{
pStk->SetError(CBotErrPrivate, p);
goto err;
@ -122,6 +122,8 @@ CBotInstr* CBotExprVar::Compile(CBotToken*& p, CBotCStack* pStack, CBotVar::Prot
{
if (p->GetNext()->GetType() == ID_OPENPAR) // a method call?
{
if (bCheckReadOnly) goto err; // don't allow increment a method call "++"
CBotInstr* i = CBotInstrMethode::Compile(p, pStk, var);
if (!pStk->IsOk()) goto err;
inst->AddNext3(i); // added after
@ -137,7 +139,7 @@ CBotInstr* CBotExprVar::Compile(CBotToken*& p, CBotCStack* pStack, CBotVar::Prot
if (var != nullptr)
{
i->SetUniqNum(var->GetUniqNum());
if (CBotFieldExpr::CheckProtectionError(pStk, preVar, var, privat))
if (CBotFieldExpr::CheckProtectionError(pStk, preVar, var, bCheckReadOnly))
{
pStk->SetError(CBotErrPrivate, pp);
goto err;

View File

@ -40,14 +40,13 @@ public:
~CBotExprVar();
/*!
* \brief Compile
* \param p
* \param pStack
* \param privat
* \brief Compile an expression of a variable, possibly chained with index operators and/or dot operators
* \param p[in, out] Pointer to first token of the expression, will be updated to point to first token after the expression
* \param pStack Current compilation stack frame
* \param bCheckReadOnly True for operations that would modify the value of the variable
* \return
*/
static CBotInstr* Compile(CBotToken*& p, CBotCStack* pStack,
CBotVar::ProtectionLevel privat = CBotVar::ProtectionLevel::Protected);
static CBotInstr* Compile(CBotToken*& p, CBotCStack* pStack, bool bCheckReadOnly = false);
/*!
* \brief CompileMethode

View File

@ -135,12 +135,11 @@ std::string CBotFieldExpr::GetDebugData()
}
////////////////////////////////////////////////////////////////////////////////
bool CBotFieldExpr::CheckProtectionError(CBotCStack* pStack, CBotVar* pPrev, CBotVar* pVar,
CBotVar::ProtectionLevel privat)
bool CBotFieldExpr::CheckProtectionError(CBotCStack* pStack, CBotVar* pPrev, CBotVar* pVar, bool bCheckReadOnly)
{
CBotVar::ProtectionLevel varPriv = pVar->GetPrivate();
if (privat == CBotVar::ProtectionLevel::ReadOnly && varPriv == privat)
if (bCheckReadOnly && varPriv == CBotVar::ProtectionLevel::ReadOnly)
return true;
if (varPriv == CBotVar::ProtectionLevel::Public) return false;

View File

@ -72,13 +72,12 @@ public:
* This function doesn't set the error flag itself.
*
* \param pStack Current compilation stack frame
* \param pPrev Class instance which variable to check is part of, or nullptr if not part of a class
* \param pPrev Class instance which variable to check is part of, or nullptr when compiler inserts 'this.' before
* \param pVar Variable to check
* \param privat CBotVar::ProtectionLevel::ReadOnly if requesting read-only access, anything else otherwise
* \param bCheckReadOnly True for operations that would modify the value of the variable
* \return true if pVar is inaccessible in the current context, false if access should be allowed
*/
static bool CheckProtectionError(CBotCStack* pStack, CBotVar* pPrev, CBotVar* pVar,
CBotVar::ProtectionLevel privat = CBotVar::ProtectionLevel::Protected);
static bool CheckProtectionError(CBotCStack* pStack, CBotVar* pPrev, CBotVar* pVar, bool bCheckReadOnly = false);
protected:
virtual const std::string GetDebugName() override { return "CBotFieldExpr"; }

View File

@ -64,7 +64,7 @@ CBotLeftExpr* CBotLeftExpr::Compile(CBotToken* &p, CBotCStack* pStack)
inst->m_nIdent = var->GetUniqNum();
if (inst->m_nIdent > 0 && inst->m_nIdent < 9000)
{
if (CBotFieldExpr::CheckProtectionError(pStk, nullptr, var, CBotVar::ProtectionLevel::ReadOnly))
if (CBotFieldExpr::CheckProtectionError(pStk, nullptr, var, true))
{
pStk->SetError(CBotErrPrivate, p);
goto err;
@ -128,8 +128,7 @@ CBotLeftExpr* CBotLeftExpr::Compile(CBotToken* &p, CBotCStack* pStack)
var = var->GetItem(p->GetString()); // get item correspondent
if (var != nullptr)
{
if (CBotFieldExpr::CheckProtectionError(pStk, preVar, var,
CBotVar::ProtectionLevel::ReadOnly))
if (CBotFieldExpr::CheckProtectionError(pStk, preVar, var, true))
{
pStk->SetError(CBotErrPrivate, pp);
goto err;

View File

@ -90,17 +90,16 @@ CBotInstr* CBotParExpr::Compile(CBotToken* &p, CBotCStack* pStack)
// post incremented or decremented?
if (IsOfType(p, ID_INC, ID_DEC))
{
// recompile the variable for read-only
delete inst;
p = pvar;
inst = CBotExprVar::Compile(p, pStk, true);
if (pStk->GetType() >= CBotTypBoolean)
{
pStk->SetError(CBotErrBadType1, pp);
delete inst;
return pStack->Return(nullptr, pStk);
}
// recompile the variable for read-only
delete inst;
p = pvar;
inst = CBotExprVar::Compile(p, pStk, CBotVar::ProtectionLevel::ReadOnly);
p = p->GetNext();
CBotPostIncExpr* i = new CBotPostIncExpr();
@ -115,24 +114,22 @@ CBotInstr* CBotParExpr::Compile(CBotToken* &p, CBotCStack* pStack)
CBotToken* pp = p;
if (IsOfType(p, ID_INC, ID_DEC))
{
CBotPreIncExpr* i = new CBotPreIncExpr();
i->SetToken(pp);
if (p->GetType() == TokenTypVar)
{
if (nullptr != (i->m_instr = CBotExprVar::Compile(p, pStk, CBotVar::ProtectionLevel::ReadOnly)))
if (nullptr != (inst = CBotExprVar::Compile(p, pStk, true)))
{
if (pStk->GetType() >= CBotTypBoolean)
if (pStk->GetType() < CBotTypBoolean) // a number ?
{
pStk->SetError(CBotErrBadType1, pp);
delete inst;
return pStack->Return(nullptr, pStk);
CBotPreIncExpr* i = new CBotPreIncExpr();
i->SetToken(pp);
i->m_instr = inst;
return pStack->Return(i, pStk);
}
return pStack->Return(i, pStk);
delete inst;
}
delete i;
return pStack->Return(nullptr, pStk);
}
pStk->SetError(CBotErrBadType1, pp);
return pStack->Return(nullptr, pStk);
}
// is it a number or DefineNum?

View File

@ -2073,3 +2073,56 @@ TEST_F(CBotUT, ClassTestPrivateMember)
CBotErrPrivate
);
}
TEST_F(CBotUT, IncrementDecrementSyntax)
{
auto publicProgram = ExecuteTest(
"public class TestClass {\n"
" int GetInt() { return 1; }\n"
"}\n"
"extern void TestIncrementDecrement()\n"
"{\n"
" int i = 1;\n"
" ASSERT(2 == ++i);\n"
" ASSERT(2 == i++);\n"
" ASSERT(3 == i );\n"
" ASSERT(2 == --i);\n"
" ASSERT(2 == i--);\n"
" ASSERT(1 == i );\n"
"}\n"
);
ExecuteTest(
"extern void PreIncrementMethodCall()\n"
"{\n"
" TestClass tc();\n"
" ++tc.GetInt();\n"
"}\n",
CBotErrBadType1
);
ExecuteTest(
"extern void PostIncrementMethodCall()\n"
"{\n"
" TestClass tc();\n"
" tc.GetInt()++;\n"
"}\n",
CBotErrBadType1
);
ExecuteTest(
"extern void BadPreIncrementEmpty()\n"
"{\n"
" ++;\n"
"}\n",
CBotErrBadType1
);
ExecuteTest(
"extern void BadPreIncrementNotAVar()\n"
"{\n"
" ++123;\n"
"}\n",
CBotErrBadType1
);
}