diff --git a/src/CBot/CBotClass.cpp b/src/CBot/CBotClass.cpp index d5007d83..27794d7f 100644 --- a/src/CBot/CBotClass.cpp +++ b/src/CBot/CBotClass.cpp @@ -19,6 +19,7 @@ #include "CBot/CBotClass.h" +#include "CBot/CBotInstr/CBotInstrUtils.h" #include "CBot/CBotInstr/CBotNew.h" #include "CBot/CBotInstr/CBotLeftExprVar.h" #include "CBot/CBotInstr/CBotTwoOpExpr.h" @@ -32,6 +33,7 @@ #include "CBot/CBotExternalCall.h" #include "CBot/CBotStack.h" #include "CBot/CBotCStack.h" +#include "CBot/CBotDefParam.h" #include "CBot/CBotUtils.h" #include "CBot/CBotFileUtils.h" #include "CBot/CBotCallMethode.h" @@ -549,6 +551,7 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond) while (pStack->IsOk()) { + CBotTypResult type2 = CBotTypResult(type); // reset type after comma std::string pp = p->GetString(); if ( IsOfType(p, ID_NOT) ) { @@ -561,29 +564,27 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond) while ( IsOfType( p, ID_OPBRK ) ) // a table? { CBotInstr* i = nullptr; - + pStack->SetStartError( p->GetStart() ); if ( p->GetType() != ID_CLBRK ) + { i = CBotExpression::Compile( p, pStack ); // expression for the value + if (i == nullptr || pStack->GetType() != CBotTypInt) // must be a number + { + pStack->SetError(CBotErrBadIndex, p->GetStart()); + return false; + } + } else i = new CBotEmpty(); // special if not a formula - type = CBotTypResult(CBotTypArrayPointer, type); - - if (!pStack->IsOk() || !IsOfType( p, ID_CLBRK ) ) - { - pStack->SetError(CBotErrCloseIndex, p->GetStart()); - return false; - } - -/* CBotVar* pv = pStack->GetVar(); - if ( pv->GetType()>= CBotTypBoolean ) - { - pStack->SetError(CBotErrBadType1, p->GetStart()); - return false; - }*/ + type2 = CBotTypResult(CBotTypArrayPointer, type2); if (limites == nullptr) limites = i; else limites->AddNext3(i); + + if (IsOfType(p, ID_CLBRK)) continue; + pStack->SetError(CBotErrCloseIndex, p->GetStart()); + return false; } if ( p->GetType() == ID_OPENPAR ) @@ -604,9 +605,14 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond) // return a method precompiled in pass 1 CBotFunction* pf = m_pMethod; CBotFunction* prev = nullptr; - while ( pf != nullptr ) + CBotToken* ppp = p; + CBotCStack* pStk = pStack->TokenStack(nullptr, true); + CBotDefParam* params = CBotDefParam::Compile(p, pStk ); + delete pStk; + p = ppp; + while ( pf != nullptr ) // search by name and parameters { - if (pf->GetName() == pp) break; + if (pf->GetName() == pp && pf->CheckParam( params )) break; prev = pf; pf = pf->Next(); } @@ -672,7 +678,7 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond) } // definition of an element - if (type.Eq(0)) + if (type2.Eq(0)) { pStack->SetError(CBotErrNoTerminator, p); return false; @@ -681,14 +687,38 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond) CBotInstr* i = nullptr; if ( IsOfType(p, ID_ASS ) ) { - if ( type.Eq(CBotTypArrayPointer) ) + pStack->SetStartError(p->GetStart()); + if ( IsOfType(p, ID_SEP) ) { - i = CBotListArray::Compile(p, pStack, type.GetTypElem()); + pStack->SetError(CBotErrNoExpression, p->GetStart()); + return false; + } + if ( type2.Eq(CBotTypArrayPointer) ) + { + if ( nullptr == (i = CBotListArray::Compile(p, pStack, type2.GetTypElem())) ) + { + if (pStack->IsOk()) + { + i = CBotTwoOpExpr::Compile(p, pStack); + if (i == nullptr || !pStack->GetTypResult().Compare(type2)) + { + pStack->SetError(CBotErrBadType1, p->GetStart()); + return false; + } + } + } } else { // it has an assignmet to calculate i = CBotTwoOpExpr::Compile(p, pStack); + + if ( !(type.Eq(CBotTypPointer) && pStack->GetTypResult().Eq(CBotTypNullPointer)) && + !TypesCompatibles( type2, pStack->GetTypResult()) ) + { + pStack->SetError(CBotErrBadType1, p->GetStart()); + return false; + } } if ( !pStack->IsOk() ) return false; } @@ -696,7 +726,7 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond) if ( !bSecond ) { - CBotVar* pv = CBotVar::Create(pp, type); + CBotVar* pv = CBotVar::Create(pp, type2); pv -> SetStatic( bStatic ); pv -> SetPrivate( mProtect ); diff --git a/src/CBot/CBotEnums.h b/src/CBot/CBotEnums.h index 475648a3..24e0095b 100644 --- a/src/CBot/CBotEnums.h +++ b/src/CBot/CBotEnums.h @@ -235,6 +235,7 @@ enum CBotError : int CBotErrBadIndex = 5040, //!< wrong index type "[ false ]" CBotErrPrivate = 5041, //!< protected item CBotErrNoPublic = 5042, //!< missing word "public" + CBotErrNoExpression = 5043, //!< expression expected after = // Runtime errors CBotErrZeroDiv = 6000, //!< division by zero diff --git a/src/CBot/CBotInstr/CBotDefArray.cpp b/src/CBot/CBotInstr/CBotDefArray.cpp index 2cb05aa0..473fdc8d 100644 --- a/src/CBot/CBotInstr/CBotDefArray.cpp +++ b/src/CBot/CBotInstr/CBotDefArray.cpp @@ -72,19 +72,26 @@ CBotInstr* CBotDefArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResul CBotInstr* i; while (IsOfType(p, ID_OPBRK)) { + pStk->SetStartError(p->GetStart()); if (p->GetType() != ID_CLBRK) - i = CBotExpression::Compile(p, pStk); // expression for the value + { + i = CBotExpression::Compile(p, pStk); // expression for the value + if (i == nullptr || pStk->GetType() != CBotTypInt) // must be a number + { + pStk->SetError(CBotErrBadIndex, p->GetStart()); + goto error; + } + } else i = new CBotEmpty(); // if no special formula inst->AddNext3b(i); // construct a list type = CBotTypResult(CBotTypArrayPointer, type); - if (!pStk->IsOk() || !IsOfType(p, ID_CLBRK )) - { - pStk->SetError(CBotErrCloseIndex, p->GetStart()); - goto error; - } + if (IsOfType(p, ID_CLBRK)) continue; + + pStk->SetError(CBotErrCloseIndex, p->GetStart()); + goto error; } CBotVar* var = CBotVar::Create(*vartoken, type); // create an instance @@ -96,17 +103,23 @@ CBotInstr* CBotDefArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResul if (IsOfType(p, ID_ASS)) // with an assignment { - if ((inst->m_listass = CBotTwoOpExpr::Compile(p, pStk)) != nullptr) + pStk->SetStartError(p->GetStart()); + if ( IsOfType(p, ID_SEP) ) { - if (!pStk->GetTypResult().Compare(type)) // compatible type ? - { - pStk->SetError(CBotErrBadType1, p->GetStart()); - goto error; - } + pStk->SetError(CBotErrNoExpression, p->GetPrev()); + goto error; } - else + if ( nullptr == (inst->m_listass = CBotListArray::Compile(p, pStk, type.GetTypElem())) ) { - inst->m_listass = CBotListArray::Compile(p, pStk, type.GetTypElem()); + if (pStk->IsOk()) + { + inst->m_listass = CBotTwoOpExpr::Compile(p, pStk); + if (inst->m_listass == nullptr || !pStk->GetTypResult().Compare(type)) // compatible type ? + { + pStk->SetError(CBotErrBadType1, p->GetStart()); + goto error; + } + } } } diff --git a/src/CBot/CBotInstr/CBotDefBoolean.cpp b/src/CBot/CBotInstr/CBotDefBoolean.cpp index bcac0722..e89bdc83 100644 --- a/src/CBot/CBotInstr/CBotDefBoolean.cpp +++ b/src/CBot/CBotInstr/CBotDefBoolean.cpp @@ -82,16 +82,17 @@ CBotInstr* CBotDefBoolean::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, inst = static_cast(CBotDefArray::Compile(p, pStk, CBotTypBoolean)); - if (!pStk->IsOk() ) - { - pStk->SetError(CBotErrCloseIndex, p->GetStart()); - goto error; - } goto suite; // no assignment, variable already created } if (IsOfType(p, ID_ASS)) { + pStk->SetStartError(p->GetStart()); + if ( IsOfType(p, ID_SEP) ) + { + pStk->SetError(CBotErrNoExpression, p->GetStart()); + goto error; + } if (nullptr == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk ))) { goto error; @@ -109,7 +110,7 @@ CBotInstr* CBotDefBoolean::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, (static_cast(inst->m_var))->m_nIdent = CBotVar::NextUniqNum()); pStack->AddVar(var); suite: - if (IsOfType(p, ID_COMMA)) + if (pStk->IsOk() && IsOfType(p, ID_COMMA)) { if (nullptr != ( inst->m_next2b = CBotDefBoolean::Compile(p, pStk, true, noskip))) { diff --git a/src/CBot/CBotInstr/CBotDefClass.cpp b/src/CBot/CBotInstr/CBotDefClass.cpp index 39ac6afa..f7ea77a6 100644 --- a/src/CBot/CBotInstr/CBotDefClass.cpp +++ b/src/CBot/CBotInstr/CBotDefClass.cpp @@ -101,11 +101,6 @@ CBotInstr* CBotDefClass::Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* p inst = static_cast(CBotDefArray::Compile(p, pStk, type )); - if (!pStk->IsOk() ) - { - pStk->SetError(CBotErrCloseIndex, p->GetStart()); - goto error; - } goto suite; // no assignment, variable already created } @@ -159,12 +154,19 @@ CBotInstr* CBotDefClass::Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* p if (IsOfType(p, ID_ASS)) // with a assignment? { + pStk->SetStartError(p->GetStart()); if (inst->m_hasParams) { pStk->SetError(CBotErrNoTerminator, p->GetStart()); goto error; } + if ( IsOfType(p, ID_SEP) ) + { + pStk->SetError(CBotErrNoExpression, p->GetStart()); + goto error; + } + if ( nullptr == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )) ) { goto error; @@ -200,7 +202,7 @@ CBotInstr* CBotDefClass::Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* p var->SetInit(CBotVar::InitType::IS_POINTER); // marks the pointer as init } suite: - if (IsOfType(p, ID_COMMA)) // several chained definitions + if (pStk->IsOk() && IsOfType(p, ID_COMMA)) // several chained definitions { if ( nullptr != ( inst->m_next = CBotDefClass::Compile(p, pStk, pClass) )) // compiles the following { @@ -208,7 +210,7 @@ suite: } } - if (IsOfType(p, ID_SEP)) // complete instruction + if (!pStk->IsOk() || IsOfType(p, ID_SEP)) // complete instruction { return pStack->Return(inst, pStk); } diff --git a/src/CBot/CBotInstr/CBotDefFloat.cpp b/src/CBot/CBotInstr/CBotDefFloat.cpp index 9a99662f..17466581 100644 --- a/src/CBot/CBotInstr/CBotDefFloat.cpp +++ b/src/CBot/CBotInstr/CBotDefFloat.cpp @@ -81,16 +81,17 @@ CBotInstr* CBotDefFloat::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, b p = vartoken; inst = static_cast(CBotDefArray::Compile(p, pStk, CBotTypFloat)); - if (!pStk->IsOk() ) - { - pStk->SetError(CBotErrCloseIndex, p->GetStart()); - goto error; - } goto suite; // no assignment, variable already created } if (IsOfType(p, ID_ASS)) { + pStk->SetStartError(p->GetStart()); + if ( IsOfType(p, ID_SEP) ) + { + pStk->SetError(CBotErrNoExpression, p->GetStart()); + goto error; + } if (nullptr == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk ))) { goto error; @@ -108,7 +109,7 @@ CBotInstr* CBotDefFloat::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, b (static_cast(inst->m_var))->m_nIdent = CBotVar::NextUniqNum()); pStack->AddVar(var); suite: - if (IsOfType(p, ID_COMMA)) + if (pStk->IsOk() && IsOfType(p, ID_COMMA)) { if (nullptr != ( inst->m_next2b = CBotDefFloat::Compile(p, pStk, true, noskip))) { diff --git a/src/CBot/CBotInstr/CBotDefInt.cpp b/src/CBot/CBotInstr/CBotDefInt.cpp index 360eb22b..4e946e9b 100644 --- a/src/CBot/CBotInstr/CBotDefInt.cpp +++ b/src/CBot/CBotInstr/CBotDefInt.cpp @@ -84,25 +84,18 @@ CBotInstr* CBotDefInt::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, boo CBotInstr* inst2 = CBotDefArray::Compile(p, pStk, CBotTypInt); - if (!pStk->IsOk() ) - { - pStk->SetError(CBotErrCloseIndex, p->GetStart()); - goto error; - } - - if (IsOfType(p, ID_COMMA)) // several definition chained - { - if (nullptr != ( inst2->m_next2b = CBotDefInt::Compile(p, pStk, true, noskip))) // compile the next one - { - return pStack->Return(inst2, pStk); - } - } inst = static_cast(inst2); goto suite; // no assignment, variable already created } if (IsOfType(p, ID_ASS)) // with an assignment? { + pStk->SetStartError(p->GetStart()); + if ( IsOfType(p, ID_SEP) ) + { + pStk->SetError(CBotErrNoExpression, p->GetStart()); + goto error; + } if (nullptr == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk ))) { goto error; @@ -121,15 +114,15 @@ CBotInstr* CBotDefInt::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, boo (static_cast(inst->m_var))->m_nIdent = CBotVar::NextUniqNum()); pStack->AddVar(var); // place it on the stack } - - if (IsOfType(p, ID_COMMA)) // chained several definitions +suite: + if (pStk->IsOk() && IsOfType(p, ID_COMMA)) // chained several definitions { if (nullptr != ( inst->m_next2b = CBotDefInt::Compile(p, pStk, true, noskip))) // compile next one { return pStack->Return(inst, pStk); } } -suite: + if (noskip || IsOfType(p, ID_SEP)) // instruction is completed { return pStack->Return(inst, pStk); diff --git a/src/CBot/CBotInstr/CBotDefString.cpp b/src/CBot/CBotInstr/CBotDefString.cpp index c878a84c..9bf2eebe 100644 --- a/src/CBot/CBotInstr/CBotDefString.cpp +++ b/src/CBot/CBotInstr/CBotDefString.cpp @@ -20,6 +20,7 @@ #include "CBot/CBotInstr/CBotDefString.h" #include "CBot/CBotInstr/CBotLeftExprVar.h" +#include "CBot/CBotInstr/CBotDefArray.h" #include "CBot/CBotInstr/CBotTwoOpExpr.h" #include "CBot/CBotStack.h" @@ -61,6 +62,7 @@ CBotInstr* CBotDefString::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, inst->m_expr = nullptr; CBotToken* vartoken = p; + CBotVar* var = nullptr; inst->SetToken(vartoken); if (nullptr != (inst->m_var = CBotLeftExprVar::Compile( p, pStk ))) @@ -73,8 +75,27 @@ CBotInstr* CBotDefString::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, goto error; } + if (IsOfType(p, ID_OPBRK)) + { + delete inst; // type is not CBotDefString + p = vartoken; // returns the variable name + + // compiles an array declaration + + CBotInstr* inst2 = CBotDefArray::Compile(p, pStk, CBotTypString); + + inst = static_cast(inst2); + goto suite; // no assignment, variable already created + } + if (IsOfType(p, ID_ASS)) { + pStk->SetStartError(p->GetStart()); + if ( IsOfType(p, ID_SEP) ) + { + pStk->SetError(CBotErrNoExpression, p->GetStart()); + goto error; + } if (nullptr == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk ))) { goto error; @@ -86,13 +107,13 @@ CBotInstr* CBotDefString::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, }*/ } - CBotVar* var = CBotVar::Create(*vartoken, CBotTypString); + var = CBotVar::Create(*vartoken, CBotTypString); var->SetInit(inst->m_expr != nullptr ? CBotVar::InitType::DEF : CBotVar::InitType::UNDEF); var->SetUniqNum( (static_cast(inst->m_var))->m_nIdent = CBotVar::NextUniqNum()); pStack->AddVar(var); - - if (IsOfType(p, ID_COMMA)) +suite: + if (pStk->IsOk() && IsOfType(p, ID_COMMA)) { if (nullptr != ( inst->m_next2b = CBotDefString::Compile(p, pStk, true, noskip))) { diff --git a/src/CBot/CBotInstr/CBotListArray.cpp b/src/CBot/CBotInstr/CBotListArray.cpp index 20a34e6e..559bb9d9 100644 --- a/src/CBot/CBotInstr/CBotListArray.cpp +++ b/src/CBot/CBotInstr/CBotListArray.cpp @@ -51,12 +51,13 @@ CBotInstr* CBotListArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResu 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(); inst->SetToken(pp); return pStack->Return(inst, pStk); // ok with empty element } + p = pp; CBotListArray* inst = new CBotListArray(); @@ -65,25 +66,45 @@ CBotInstr* CBotListArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResu // each element takes the one after the other if (type.Eq( CBotTypArrayPointer )) { - type = type.GetTypElem(); - pStk->SetStartError(p->GetStart()); - if (nullptr == ( inst->m_expr = CBotListArray::Compile( p, pStk, type ) )) + if (nullptr == ( inst->m_expr = CBotListArray::Compile( p, pStk, type.GetTypElem() ) )) { - goto error; + if (pStk->IsOk()) + { + inst->m_expr = CBotTwoOpExpr::Compile(p, pStk); + if (inst->m_expr == nullptr || !pStk->GetTypResult().Compare(type)) // compatible type ? + { + pStk->SetError(CBotErrBadType1, p->GetStart()); + goto error; + } + } } while (IsOfType( p, ID_COMMA )) // other elements? { pStk->SetStartError(p->GetStart()); - CBotInstr* i = CBotListArray::Compile(p, pStk, type); - if (nullptr == i) + CBotInstr* i = nullptr; + if (nullptr == ( i = CBotListArray::Compile(p, pStk, type.GetTypElem() ) )) { - goto error; + if (pStk->IsOk()) + { + i = CBotTwoOpExpr::Compile(p, pStk); + if (i == nullptr || !pStk->GetTypResult().Compare(type)) // compatible type ? + { + pStk->SetError(CBotErrBadType1, p->GetStart()); + goto error; + } + } } inst->m_expr->AddNext3(i); + + if ( p->GetType() == ID_COMMA ) continue; + if ( p->GetType() == ID_CLBLK ) break; + + pStk->SetError(CBotErrClosePar, p); + goto error; } } else @@ -95,7 +116,8 @@ CBotInstr* CBotListArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResu } CBotVar* pv = pStk->GetVar(); // result of the expression - if (pv == nullptr || !TypesCompatibles( type, pv->GetTypResult())) // compatible type? + if (pv == nullptr || (!TypesCompatibles( type, pv->GetTypResult()) && + !(type.Eq(CBotTypPointer) && pv->GetTypResult().Eq(CBotTypNullPointer)) )) { pStk->SetError(CBotErrBadType1, p->GetStart()); goto error; @@ -113,12 +135,19 @@ CBotInstr* CBotListArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResu CBotVar* pv = pStk->GetVar(); // result of the expression - if (pv == nullptr || !TypesCompatibles( type, pv->GetTypResult())) // compatible type? + if (pv == nullptr || (!TypesCompatibles( type, pv->GetTypResult()) && + !(type.Eq(CBotTypPointer) && pv->GetTypResult().Eq(CBotTypNullPointer)) )) { pStk->SetError(CBotErrBadType1, p->GetStart()); goto error; } inst->m_expr->AddNext3(i); + + if (p->GetType() == ID_COMMA) continue; + if (p->GetType() == ID_CLBLK) break; + + pStk->SetError(CBotErrClosePar, p); + goto error; } } diff --git a/src/common/restext.cpp b/src/common/restext.cpp index 1ef49306..96e51e0d 100644 --- a/src/common/restext.cpp +++ b/src/common/restext.cpp @@ -715,6 +715,7 @@ void InitializeRestext() stringsCbot[CBot::CBotErrBadIndex] = TR("Incorrect index type"); stringsCbot[CBot::CBotErrPrivate] = TR("Private element"); stringsCbot[CBot::CBotErrNoPublic] = TR("Public required"); + stringsCbot[CBot::CBotErrNoExpression] = TR("expression expected after ="); stringsCbot[CBot::CBotErrZeroDiv] = TR("Dividing by zero"); stringsCbot[CBot::CBotErrNotInit] = TR("Variable not initialized");