Merge pull request #920 from melex750/dev

Fix default arguments
master
krzys_h 2017-05-22 10:58:16 +02:00 committed by GitHub
commit cd808ac59f
6 changed files with 144 additions and 43 deletions

View File

@ -136,30 +136,38 @@ bool CBotDefParam::Execute(CBotVar** ppVars, CBotStack* &pj)
CBotDefParam* p = this; CBotDefParam* p = this;
bool useDefault = false; bool useDefault = false;
CBotStack* pile = pj->AddStack();
while ( p != nullptr ) while ( p != nullptr )
{ {
// creates a local variable on the stack pile = pile->AddStack();
CBotVar* newvar = CBotVar::Create(p->m_token.GetString(), p->m_type); if (pile->GetState() == 1) // already done?
{
if (ppVars != nullptr && ppVars[i] != nullptr) ++i;
p = p->m_next;
continue; // next param
}
CBotVar* pVar = nullptr; CBotVar* pVar = nullptr;
CBotStack* pile = nullptr; // stack for default expression
if (useDefault || (ppVars == nullptr || ppVars[i] == nullptr)) if (useDefault || (ppVars == nullptr || ppVars[i] == nullptr))
{ {
assert(p->m_expr != nullptr); assert(p->m_expr != nullptr);
pile = pj->AddStack();
useDefault = true; useDefault = true;
while (pile->IsOk() && !p->m_expr->Execute(pile)); if (!p->m_expr->Execute(pile)) return false; // interupt here
if (!pile->IsOk()) return pj->Return(pile); // return the error
pVar = pile->GetVar(); pVar = pile->GetVar();
} }
else else
pVar = ppVars[i]; pVar = ppVars[i];
pile->SetState(1); // mark this param done
// 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: // serves to make the transformation of types:
if ((useDefault && pVar != nullptr) || if ((useDefault && pVar != nullptr) ||
(ppVars != nullptr && pVar != nullptr)) (ppVars != nullptr && pVar != nullptr))
@ -202,7 +210,6 @@ bool CBotDefParam::Execute(CBotVar** ppVars, CBotStack* &pj)
pj->AddVar(newvar); // add a variable pj->AddVar(newvar); // add a variable
p = p->m_next; p = p->m_next;
if (!useDefault) i++; if (!useDefault) i++;
if (pile != nullptr) pile->Delete();
} }
return true; return true;
@ -217,14 +224,27 @@ bool CBotDefParam::HasDefault()
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void CBotDefParam::RestoreState(CBotStack* &pj, bool bMain) void CBotDefParam::RestoreState(CBotStack* &pj, bool bMain)
{ {
// int i = 0; assert(this != nullptr);
CBotDefParam* p = this; CBotDefParam* p = this;
CBotStack* pile = nullptr;
if (bMain) pile = pj->RestoreStack();
while ( p != nullptr ) while ( p != nullptr )
{ {
if (bMain && pile != nullptr)
{
pile = pile->RestoreStack();
if (pile != nullptr && pile->GetState() == 0)
{
assert(p->m_expr != nullptr);
p->m_expr->RestoreState(pile, true);
return;
}
}
// creates a local variable on the stack // creates a local variable on the stack
CBotVar* var = pj->FindVar(p->m_token.GetString()); CBotVar* var = pj->FindVar(p->m_token.GetString());
var->SetUniqNum(p->m_nIdent); if (var != nullptr) var->SetUniqNum(p->m_nIdent);
p = p->m_next; p = p->m_next;
} }
} }

View File

@ -41,7 +41,7 @@ CBotExprUnaire::~CBotExprUnaire()
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
CBotInstr* CBotExprUnaire::Compile(CBotToken* &p, CBotCStack* pStack) CBotInstr* CBotExprUnaire::Compile(CBotToken* &p, CBotCStack* pStack, bool bLiteral)
{ {
int op = p->GetType(); int op = p->GetType();
CBotToken* pp = p; CBotToken* pp = p;
@ -52,7 +52,10 @@ CBotInstr* CBotExprUnaire::Compile(CBotToken* &p, CBotCStack* pStack)
CBotExprUnaire* inst = new CBotExprUnaire(); CBotExprUnaire* inst = new CBotExprUnaire();
inst->SetToken(pp); inst->SetToken(pp);
if (nullptr != (inst->m_expr = CBotParExpr::Compile(p, pStk ))) if (!bLiteral) inst->m_expr = CBotParExpr::Compile(p, pStk);
else inst->m_expr = CBotParExpr::CompileLitExpr(p, pStk);
if (inst->m_expr != nullptr)
{ {
if (op == ID_ADD && pStk->GetType() < CBotTypBoolean) // only with the number if (op == ID_ADD && pStk->GetType() < CBotTypBoolean) // only with the number
return pStack->Return(inst, pStk); return pStack->Return(inst, pStk);

View File

@ -34,12 +34,13 @@ public:
~CBotExprUnaire(); ~CBotExprUnaire();
/*! /*!
* \brief Compile * \brief Compile an expression with a unary operator
* \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
* \return * \param bLiteral If true, compiles only literal expressions Ex: ~11, -4.0, !false, not true
* \return The compiled instruction or nullptr
*/ */
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack); static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool bLiteral = false);
/*! /*!
* \brief Execute * \brief Execute

View File

@ -370,11 +370,18 @@ bool CBotFunction::Execute(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance)
pile->SetProgram(m_pProg); // bases for routines pile->SetProgram(m_pProg); // bases for routines
if ( pile->IfStep() ) return false;
if ( pile->GetState() == 0 ) if ( pile->GetState() == 0 )
{ {
if (m_param != nullptr) if (m_param != nullptr)
{ {
// stack for parameters and default args
CBotStack* pile3b = pile->AddStack();
pile3b->SetState(1);
if ( !m_param->Execute(ppVars, pile) ) return false; // define parameters if ( !m_param->Execute(ppVars, pile) ) return false; // define parameters
pile3b->Delete(); // done with param stack
} }
pile->IncState(); pile->IncState();
} }
@ -408,8 +415,6 @@ bool CBotFunction::Execute(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance)
pile->IncState(); pile->IncState();
} }
if ( pile->IfStep() ) return false;
if ( !m_block->Execute(pile) ) if ( !m_block->Execute(pile) )
{ {
if ( pile->GetError() < 0 ) if ( pile->GetError() < 0 )
@ -438,7 +443,22 @@ void CBotFunction::RestoreState(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInst
pile2->Delete(); pile2->Delete();
} }
m_param->RestoreState(pile2, true); // parameters if ( pile->GetState() == 0 )
{
if (m_param != nullptr)
{
CBotStack* pile3b = pile2->RestoreStack();
if (pile3b != nullptr && pile3b->GetState() == 1)
m_param->RestoreState(pile2, true); // restore executing default arguments
else
m_param->RestoreState(pile2, false); // restore parameter IDs
}
return;
}
if (m_param != nullptr)
m_param->RestoreState(pile2, false); // restore parameter IDs
if ( !m_MasterClass.empty() ) if ( !m_MasterClass.empty() )
{ {
@ -670,7 +690,10 @@ int CBotFunction::DoCall(CBotProgram* program, const std::list<CBotFunction*>& l
if ( pStk1->GetState() == 0 ) if ( pStk1->GetState() == 0 )
{ {
if ( !pt->m_MasterClass.empty() ) // stack for parameters and default args
CBotStack* pStk3b = pStk3->AddStack();
if (pStk3b->GetState() == 0 && !pt->m_MasterClass.empty())
{ {
CBotVar* pInstance = program->m_thisVar; CBotVar* pInstance = program->m_thisVar;
// make "this" known // make "this" known
@ -696,20 +719,21 @@ int CBotFunction::DoCall(CBotProgram* program, const std::list<CBotFunction*>& l
pThis->SetUniqNum(-2); pThis->SetUniqNum(-2);
pStk1->AddVar(pThis); pStk1->AddVar(pThis);
} }
pStk3b->SetState(1); // set 'this' was created
// initializes the variables as parameters // initializes the variables as parameters
if (pt->m_param != nullptr) if (pt->m_param != nullptr)
{ {
if (!pt->m_param->Execute(ppVars, pStk3)) // interupts only if error on a default value if (!pt->m_param->Execute(ppVars, pStk3)) // interupt here
{ {
if ( pt->m_pProg != program ) if (!pStk3->IsOk() && pt->m_pProg != program)
{ {
pStk3->SetPosError(pToken); // indicates the error on the procedure call pStk3->SetPosError(pToken); // indicates the error on the procedure call
} }
return pStack->Return(pStk3); return false;
} }
} }
pStk3b->Delete(); // done with param stack
pStk1->IncState(); pStk1->IncState();
} }
@ -778,12 +802,21 @@ void CBotFunction::RestoreCall(const std::list<CBotFunction*>& localFunctionList
if ( pStk1->GetState() == 0 ) if ( pStk1->GetState() == 0 )
{ {
pt->m_param->RestoreState(pStk3, true); if (pt->m_param != nullptr)
{
CBotStack* pStk3b = pStk3->RestoreStack();
if (pStk3b != nullptr && pStk3b->GetState() == 1)
pt->m_param->RestoreState(pStk3, true); // restore executing default arguments
else
pt->m_param->RestoreState(pStk3, false); // restore parameter IDs
}
return; return;
} }
// initializes the variables as parameters // initializes the variables as parameters
pt->m_param->RestoreState(pStk3, false); if (pt->m_param != nullptr)
pt->m_param->RestoreState(pStk3, false); // restore parameter IDs
pt->m_block->RestoreState(pStk3, true); pt->m_block->RestoreState(pStk3, true);
} }
} }
@ -811,33 +844,42 @@ int CBotFunction::DoCall(const std::list<CBotFunction*>& localFunctionList, long
if ( pStk->GetState() == 0 ) if ( pStk->GetState() == 0 )
{ {
// sets the variable "this" on the stack // stack for parameters and default args
CBotVar* pthis = CBotVar::Create("this", CBotTypNullPointer); CBotStack* pStk3b = pStk3->AddStack();
pthis->Copy(pThis, false);
pthis->SetUniqNum(-2); // special value
pStk->AddVar(pthis);
CBotClass* pClass = pThis->GetClass()->GetParent(); if (pStk3b->GetState() == 0)
if ( pClass )
{ {
// sets the variable "super" on the stack // sets the variable "this" on the stack
CBotVar* psuper = CBotVar::Create("super", CBotTypNullPointer); CBotVar* pthis = CBotVar::Create("this", CBotTypNullPointer);
psuper->Copy(pThis, false); // in fact identical to "this" pthis->Copy(pThis, false);
psuper->SetUniqNum(-3); // special value pthis->SetUniqNum(-2); // special value
pStk->AddVar(psuper); 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);
}
} }
pStk3b->SetState(1); // set 'this' was created
// initializes the variables as parameters // initializes the variables as parameters
if (pt->m_param != nullptr) if (pt->m_param != nullptr)
{ {
if (!pt->m_param->Execute(ppVars, pStk3)) // interupts only if error on a default value if (!pt->m_param->Execute(ppVars, pStk3)) // interupt here
{ {
if ( pt->m_pProg != pProgCurrent ) if (!pStk3->IsOk() && pt->m_pProg != pProgCurrent)
{ {
pStk3->SetPosError(pToken); // indicates the error on the procedure call pStk3->SetPosError(pToken); // indicates the error on the procedure call
} }
return pStack->Return(pStk3); return false;
} }
} }
pStk3b->Delete(); // done with param stack
pStk->IncState(); pStk->IncState();
} }
@ -905,7 +947,21 @@ bool CBotFunction::RestoreCall(const std::list<CBotFunction*>& localFunctionList
CBotStack* pStk3 = pStk->RestoreStack(nullptr); // to set parameters passed CBotStack* pStk3 = pStk->RestoreStack(nullptr); // to set parameters passed
if ( pStk3 == nullptr ) return true; if ( pStk3 == nullptr ) return true;
pt->m_param->RestoreState(pStk3, true); // parameters if ( pStk->GetState() == 0 )
{
if (pt->m_param != nullptr)
{
CBotStack* pStk3b = pStk3->RestoreStack();
if (pStk3b != nullptr && pStk3b->GetState() == 1)
pt->m_param->RestoreState(pStk3, true); // restore executing default arguments
else
pt->m_param->RestoreState(pStk3, false); // restore parameter IDs
}
return true;
}
if (pt->m_param != nullptr)
pt->m_param->RestoreState(pStk3, false); // restore parameter IDs
if ( pStk->GetState() > 1 && // latching is effective? if ( pStk->GetState() > 1 && // latching is effective?
pt->m_bSynchro ) pt->m_bSynchro )

View File

@ -132,7 +132,7 @@ CBotInstr* CBotParExpr::Compile(CBotToken* &p, CBotCStack* pStack)
return pStack->Return(nullptr, pStk); return pStack->Return(nullptr, pStk);
} }
return CompileLitExpr(p, pStack); return CBotParExpr::CompileLitExpr(p, pStack);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -142,6 +142,11 @@ CBotInstr* CBotParExpr::CompileLitExpr(CBotToken* &p, CBotCStack* pStack)
CBotToken* pp = p; CBotToken* pp = p;
// is this a unary operation?
CBotInstr* inst = CBotExprUnaire::Compile(p, pStk, true);
if (inst != nullptr || !pStk->IsOk())
return pStack->Return(inst, pStk);
// is it a number or DefineNum? // is it a number or DefineNum?
if (p->GetType() == TokenTypNum || if (p->GetType() == TokenTypNum ||
p->GetType() == TokenTypDef ) p->GetType() == TokenTypDef )

View File

@ -2385,4 +2385,20 @@ TEST_F(CBotUT, ParametersWithDefaultValues)
"\n", "\n",
CBotErrAmbiguousCall CBotErrAmbiguousCall
); );
ExecuteTest(
"extern void DefaultValueUnaryExpression() {\n"
" TestNumbers();\n"
" TestBool();\n"
"}\n"
"void TestNumbers(int i = -1, float f = -1, int ii = ~1) {\n"
" ASSERT(i == -1);\n"
" ASSERT(f == -1.0);\n"
" ASSERT(ii == ~1);\n"
"}\n"
"void TestBool(bool b = !false, bool b2 = not false) {\n"
" ASSERT(true == b);\n"
" ASSERT(true == b2);\n"
"}\n"
);
} }