Fix increment and decrement syntax
parent
d7fae300b9
commit
8fc0151444
|
@ -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;
|
// CBotToken* pDebut = p;
|
||||||
CBotCStack* pStk = pStack->TokenStack();
|
CBotCStack* pStk = pStack->TokenStack();
|
||||||
|
@ -67,7 +67,7 @@ CBotInstr* CBotExprVar::Compile(CBotToken*& p, CBotCStack* pStack, CBotVar::Prot
|
||||||
|
|
||||||
if (ident > 0 && ident < 9000)
|
if (ident > 0 && ident < 9000)
|
||||||
{
|
{
|
||||||
if (CBotFieldExpr::CheckProtectionError(pStk, nullptr, var, privat))
|
if (CBotFieldExpr::CheckProtectionError(pStk, nullptr, var, bCheckReadOnly))
|
||||||
{
|
{
|
||||||
pStk->SetError(CBotErrPrivate, p);
|
pStk->SetError(CBotErrPrivate, p);
|
||||||
goto err;
|
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 (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);
|
CBotInstr* i = CBotInstrMethode::Compile(p, pStk, var);
|
||||||
if (!pStk->IsOk()) goto err;
|
if (!pStk->IsOk()) goto err;
|
||||||
inst->AddNext3(i); // added after
|
inst->AddNext3(i); // added after
|
||||||
|
@ -137,7 +139,7 @@ CBotInstr* CBotExprVar::Compile(CBotToken*& p, CBotCStack* pStack, CBotVar::Prot
|
||||||
if (var != nullptr)
|
if (var != nullptr)
|
||||||
{
|
{
|
||||||
i->SetUniqNum(var->GetUniqNum());
|
i->SetUniqNum(var->GetUniqNum());
|
||||||
if (CBotFieldExpr::CheckProtectionError(pStk, preVar, var, privat))
|
if (CBotFieldExpr::CheckProtectionError(pStk, preVar, var, bCheckReadOnly))
|
||||||
{
|
{
|
||||||
pStk->SetError(CBotErrPrivate, pp);
|
pStk->SetError(CBotErrPrivate, pp);
|
||||||
goto err;
|
goto err;
|
||||||
|
|
|
@ -40,14 +40,13 @@ public:
|
||||||
~CBotExprVar();
|
~CBotExprVar();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Compile
|
* \brief Compile an expression of a variable, possibly chained with index operators and/or dot operators
|
||||||
* \param p
|
* \param p[in, out] Pointer to first token of the expression, will be updated to point to first token after the expression
|
||||||
* \param pStack
|
* \param pStack Current compilation stack frame
|
||||||
* \param privat
|
* \param bCheckReadOnly True for operations that would modify the value of the variable
|
||||||
* \return
|
* \return
|
||||||
*/
|
*/
|
||||||
static CBotInstr* Compile(CBotToken*& p, CBotCStack* pStack,
|
static CBotInstr* Compile(CBotToken*& p, CBotCStack* pStack, bool bCheckReadOnly = false);
|
||||||
CBotVar::ProtectionLevel privat = CBotVar::ProtectionLevel::Protected);
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief CompileMethode
|
* \brief CompileMethode
|
||||||
|
|
|
@ -135,12 +135,11 @@ std::string CBotFieldExpr::GetDebugData()
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
bool CBotFieldExpr::CheckProtectionError(CBotCStack* pStack, CBotVar* pPrev, CBotVar* pVar,
|
bool CBotFieldExpr::CheckProtectionError(CBotCStack* pStack, CBotVar* pPrev, CBotVar* pVar, bool bCheckReadOnly)
|
||||||
CBotVar::ProtectionLevel privat)
|
|
||||||
{
|
{
|
||||||
CBotVar::ProtectionLevel varPriv = pVar->GetPrivate();
|
CBotVar::ProtectionLevel varPriv = pVar->GetPrivate();
|
||||||
|
|
||||||
if (privat == CBotVar::ProtectionLevel::ReadOnly && varPriv == privat)
|
if (bCheckReadOnly && varPriv == CBotVar::ProtectionLevel::ReadOnly)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (varPriv == CBotVar::ProtectionLevel::Public) return false;
|
if (varPriv == CBotVar::ProtectionLevel::Public) return false;
|
||||||
|
|
|
@ -72,13 +72,12 @@ public:
|
||||||
* This function doesn't set the error flag itself.
|
* This function doesn't set the error flag itself.
|
||||||
*
|
*
|
||||||
* \param pStack Current compilation stack frame
|
* \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 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
|
* \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,
|
static bool CheckProtectionError(CBotCStack* pStack, CBotVar* pPrev, CBotVar* pVar, bool bCheckReadOnly = false);
|
||||||
CBotVar::ProtectionLevel privat = CBotVar::ProtectionLevel::Protected);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual const std::string GetDebugName() override { return "CBotFieldExpr"; }
|
virtual const std::string GetDebugName() override { return "CBotFieldExpr"; }
|
||||||
|
|
|
@ -64,7 +64,7 @@ CBotLeftExpr* CBotLeftExpr::Compile(CBotToken* &p, CBotCStack* pStack)
|
||||||
inst->m_nIdent = var->GetUniqNum();
|
inst->m_nIdent = var->GetUniqNum();
|
||||||
if (inst->m_nIdent > 0 && inst->m_nIdent < 9000)
|
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);
|
pStk->SetError(CBotErrPrivate, p);
|
||||||
goto err;
|
goto err;
|
||||||
|
@ -128,8 +128,7 @@ CBotLeftExpr* CBotLeftExpr::Compile(CBotToken* &p, CBotCStack* pStack)
|
||||||
var = var->GetItem(p->GetString()); // get item correspondent
|
var = var->GetItem(p->GetString()); // get item correspondent
|
||||||
if (var != nullptr)
|
if (var != nullptr)
|
||||||
{
|
{
|
||||||
if (CBotFieldExpr::CheckProtectionError(pStk, preVar, var,
|
if (CBotFieldExpr::CheckProtectionError(pStk, preVar, var, true))
|
||||||
CBotVar::ProtectionLevel::ReadOnly))
|
|
||||||
{
|
{
|
||||||
pStk->SetError(CBotErrPrivate, pp);
|
pStk->SetError(CBotErrPrivate, pp);
|
||||||
goto err;
|
goto err;
|
||||||
|
|
|
@ -90,17 +90,16 @@ CBotInstr* CBotParExpr::Compile(CBotToken* &p, CBotCStack* pStack)
|
||||||
// post incremented or decremented?
|
// post incremented or decremented?
|
||||||
if (IsOfType(p, ID_INC, ID_DEC))
|
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)
|
if (pStk->GetType() >= CBotTypBoolean)
|
||||||
{
|
{
|
||||||
pStk->SetError(CBotErrBadType1, pp);
|
pStk->SetError(CBotErrBadType1, pp);
|
||||||
delete inst;
|
delete inst;
|
||||||
return pStack->Return(nullptr, pStk);
|
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();
|
p = p->GetNext();
|
||||||
|
|
||||||
CBotPostIncExpr* i = new CBotPostIncExpr();
|
CBotPostIncExpr* i = new CBotPostIncExpr();
|
||||||
|
@ -115,24 +114,22 @@ CBotInstr* CBotParExpr::Compile(CBotToken* &p, CBotCStack* pStack)
|
||||||
CBotToken* pp = p;
|
CBotToken* pp = p;
|
||||||
if (IsOfType(p, ID_INC, ID_DEC))
|
if (IsOfType(p, ID_INC, ID_DEC))
|
||||||
{
|
{
|
||||||
CBotPreIncExpr* i = new CBotPreIncExpr();
|
|
||||||
i->SetToken(pp);
|
|
||||||
|
|
||||||
if (p->GetType() == TokenTypVar)
|
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);
|
CBotPreIncExpr* i = new CBotPreIncExpr();
|
||||||
delete inst;
|
i->SetToken(pp);
|
||||||
return pStack->Return(nullptr, pStk);
|
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?
|
// is it a number or DefineNum?
|
||||||
|
|
|
@ -2073,3 +2073,56 @@ TEST_F(CBotUT, ClassTestPrivateMember)
|
||||||
CBotErrPrivate
|
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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue