Fix syntax and type checking for CBotListArray
parent
51201f15e1
commit
4a29e8406d
|
@ -45,57 +45,111 @@ CBotListArray::~CBotListArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
CBotInstr* CBotListArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResult type)
|
CBotInstr* CBotListArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResult type, bool classItem)
|
||||||
{
|
{
|
||||||
CBotCStack* pStk = pStack->TokenStack(p);
|
CBotCStack* pStk = pStack->TokenStack(p);
|
||||||
|
|
||||||
CBotToken* pp = p;
|
CBotToken* pp = p;
|
||||||
|
|
||||||
if (IsOfType( p, ID_NULL ))
|
if (IsOfType( p, ID_NULL ) || (IsOfType(p, ID_OPBLK) && IsOfType(p, ID_CLBLK)))
|
||||||
{
|
{
|
||||||
CBotInstr* inst = new CBotExprLitNull();
|
CBotInstr* inst = new CBotExprLitNull();
|
||||||
inst->SetToken(pp);
|
inst->SetToken(pp);
|
||||||
return pStack->Return(inst, pStk); // ok with empty element
|
return pStack->Return(inst, pStk); // ok with empty element
|
||||||
}
|
}
|
||||||
|
p = pp;
|
||||||
|
|
||||||
CBotListArray* inst = new CBotListArray();
|
CBotListArray* inst = new CBotListArray();
|
||||||
|
|
||||||
|
pStk->SetStartError(p->GetStart());
|
||||||
|
|
||||||
if (IsOfType( p, ID_OPBLK ))
|
if (IsOfType( p, ID_OPBLK ))
|
||||||
{
|
{
|
||||||
// each element takes the one after the other
|
// each element takes the one after the other
|
||||||
if (type.Eq( CBotTypArrayPointer ))
|
if (type.Eq( CBotTypArrayPointer ))
|
||||||
{
|
{
|
||||||
type = type.GetTypElem();
|
|
||||||
|
|
||||||
pStk->SetStartError(p->GetStart());
|
pStk->SetStartError(p->GetStart());
|
||||||
if (nullptr == ( inst->m_expr = CBotListArray::Compile( p, pStk, type ) ))
|
if (p->GetType() == TokenTypVar)
|
||||||
{
|
{
|
||||||
goto error;
|
if (!classItem)
|
||||||
|
{
|
||||||
|
inst->m_expr = CBotTwoOpExpr::Compile(p, pStk);
|
||||||
|
if (!pStk->GetTypResult().Compare(type)) // compatible type ?
|
||||||
|
{
|
||||||
|
pStk->SetError(CBotErrBadType1, p->GetStart());
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pStk->SetError(CBotErrBadLeft, p->GetPrev());
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
while (IsOfType( p, ID_COMMA )) // other elements?
|
|
||||||
{
|
{
|
||||||
pStk->SetStartError(p->GetStart());
|
if (nullptr == ( inst->m_expr = CBotListArray::Compile( p, pStk, type.GetTypElem() ) ))
|
||||||
|
|
||||||
CBotInstr* i = CBotListArray::Compile(p, pStk, type);
|
|
||||||
if (nullptr == i)
|
|
||||||
{
|
{
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
while (IsOfType( p, ID_COMMA )) // other elements?
|
||||||
|
{
|
||||||
|
pStk->SetStartError(p->GetStart());
|
||||||
|
CBotInstr* i = nullptr;
|
||||||
|
if (p->GetType() == TokenTypVar)
|
||||||
|
{
|
||||||
|
if (!classItem)
|
||||||
|
{
|
||||||
|
i = CBotTwoOpExpr::Compile(p, pStk);
|
||||||
|
if (nullptr == i || !pStk->GetTypResult().Compare(type)) // compatible type ?
|
||||||
|
{
|
||||||
|
pStk->SetError(CBotErrBadType1, p->GetStart());
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pStk->SetError(CBotErrBadLeft, p->GetPrev());
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
i = CBotListArray::Compile(p, pStk, type.GetTypElem());
|
||||||
|
if (nullptr == i)
|
||||||
|
{
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
inst->m_expr->AddNext3(i);
|
inst->m_expr->AddNext3(i);
|
||||||
|
if ( p->GetType() == ID_COMMA ) continue;
|
||||||
|
if ( p->GetType() == ID_CLBLK ) break;
|
||||||
|
|
||||||
|
pStk->SetError(CBotErrClosePar, p);
|
||||||
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pStk->SetStartError(p->GetStart());
|
pStk->SetStartError(p->GetStart());
|
||||||
|
if (classItem && IsOfType(p, TokenTypVar, ID_NEW)) // don't allow func() or var between "{ }"
|
||||||
|
{
|
||||||
|
pStk->SetError(CBotErrBadLeft, p->GetPrev());
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
if (nullptr == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )))
|
if (nullptr == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )))
|
||||||
{
|
{
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
CBotVar* pv = pStk->GetVar(); // result of the expression
|
CBotVar* pv = pStk->GetVar(); // result of the expression
|
||||||
|
CBotTypResult retType;
|
||||||
|
if (pv != nullptr) retType = pv->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC);
|
||||||
|
|
||||||
if (pv == nullptr || !TypesCompatibles( type, pv->GetTypResult())) // compatible type?
|
if (pv == nullptr || (type.Eq(CBotTypString) && !retType.Eq(CBotTypString)) ||
|
||||||
|
(!(type.Eq(CBotTypPointer) && retType.Eq(CBotTypNullPointer)) &&
|
||||||
|
!TypesCompatibles( type, pv->GetTypResult()) &&
|
||||||
|
!TypeCompatible(type, retType, ID_ASS) ) ) // compatible type?
|
||||||
{
|
{
|
||||||
pStk->SetError(CBotErrBadType1, p->GetStart());
|
pStk->SetError(CBotErrBadType1, p->GetStart());
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -105,6 +159,12 @@ CBotInstr* CBotListArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResu
|
||||||
{
|
{
|
||||||
pStk->SetStartError(p->GetStart());
|
pStk->SetStartError(p->GetStart());
|
||||||
|
|
||||||
|
if (classItem && IsOfType(p, TokenTypVar, ID_NEW)) // don't allow func() or var between "{ }"
|
||||||
|
{
|
||||||
|
pStk->SetError(CBotErrBadLeft, p);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
CBotInstr* i = CBotTwoOpExpr::Compile(p, pStk) ;
|
CBotInstr* i = CBotTwoOpExpr::Compile(p, pStk) ;
|
||||||
if (nullptr == i)
|
if (nullptr == i)
|
||||||
{
|
{
|
||||||
|
@ -112,13 +172,24 @@ CBotInstr* CBotListArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResu
|
||||||
}
|
}
|
||||||
|
|
||||||
CBotVar* pv = pStk->GetVar(); // result of the expression
|
CBotVar* pv = pStk->GetVar(); // result of the expression
|
||||||
|
CBotTypResult retType;
|
||||||
|
if (pv != nullptr) retType = pv->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC);
|
||||||
|
|
||||||
if (pv == nullptr || !TypesCompatibles( type, pv->GetTypResult())) // compatible type?
|
if (pv == nullptr || (type.Eq(CBotTypString) && !retType.Eq(CBotTypString)) ||
|
||||||
|
(!(type.Eq(CBotTypPointer) && retType.Eq(CBotTypNullPointer)) &&
|
||||||
|
!TypesCompatibles( type, pv->GetTypResult()) &&
|
||||||
|
!TypeCompatible(type, retType, ID_ASS) ) ) // compatible type?
|
||||||
{
|
{
|
||||||
pStk->SetError(CBotErrBadType1, p->GetStart());
|
pStk->SetError(CBotErrBadType1, p->GetStart());
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
inst->m_expr->AddNext3(i);
|
inst->m_expr->AddNext3(i);
|
||||||
|
|
||||||
|
if (p->GetType() == ID_COMMA) continue;
|
||||||
|
if (p->GetType() == ID_CLBLK) break;
|
||||||
|
|
||||||
|
pStk->SetError(CBotErrClosePar, p);
|
||||||
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,9 +38,10 @@ public:
|
||||||
* \param p
|
* \param p
|
||||||
* \param pStack
|
* \param pStack
|
||||||
* \param type
|
* \param type
|
||||||
|
* \param classItem
|
||||||
* \return
|
* \return
|
||||||
*/
|
*/
|
||||||
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResult type);
|
static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResult type, bool classItem = false);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Execute Executes the definition of an array.
|
* \brief Execute Executes the definition of an array.
|
||||||
|
|
Loading…
Reference in New Issue