Fix constructor/destructor and field syntax

dev-buzzingcars
melex750 2017-01-16 12:34:18 -05:00 committed by krzys_h
parent 8fc0151444
commit 64bc1f1afb
11 changed files with 167 additions and 33 deletions

View File

@ -1736,6 +1736,9 @@ msgstr ""
msgid "Ambiguous call to overloaded function"
msgstr ""
msgid "Function needs return type \"void\""
msgstr ""
msgid "Dividing by zero"
msgstr ""

View File

@ -616,6 +616,9 @@ msgstr "Diese Funktion gibt es schon"
msgid "Function name missing"
msgstr "Hier muss der Name der Funktion stehen"
msgid "Function needs return type \"void\""
msgstr ""
msgid "Game speed"
msgstr "Spielgeschwindigkeit"

View File

@ -603,6 +603,9 @@ msgstr "Cette fonction existe déjà"
msgid "Function name missing"
msgstr "Nom de la fonction attendu"
msgid "Function needs return type \"void\""
msgstr ""
msgid "Game speed"
msgstr "Vitesse du jeu"

View File

@ -605,6 +605,9 @@ msgstr "Funkcja już istnieje"
msgid "Function name missing"
msgstr "Brakująca nazwa funkcji"
msgid "Function needs return type \"void\""
msgstr ""
msgid "Game speed"
msgstr "Prędkość gry"

View File

@ -612,6 +612,9 @@ msgstr "Функция уже существует"
msgid "Function name missing"
msgstr "Имя функции отсутствует"
msgid "Function needs return type \"void\""
msgstr ""
msgid "Game speed"
msgstr "Скорость игры"

View File

@ -248,6 +248,19 @@ CBotVar* CBotClass::GetItemRef(int nIdent)
return nullptr;
}
////////////////////////////////////////////////////////////////////////////////
bool CBotClass::CheckVar(const std::string &name)
{
CBotVar* p = m_pVar;
while ( p != nullptr )
{
if ( p->GetName() == name ) return true;
p = p->GetNext();
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool CBotClass::IsIntrinsic()
{
@ -556,6 +569,8 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
while (pStack->IsOk())
{
CBotTypResult type2 = CBotTypResult(type); // reset type after comma
CBotToken* varToken = p;
std::string pp = p->GetString();
if ( IsOfType(p, ID_NOT) )
{
@ -564,33 +579,6 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
if (IsOfType(p, TokenTypVar))
{
CBotInstr* limites = nullptr;
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
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 )
{
if ( !bSecond )
@ -673,12 +661,51 @@ bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
}
// definition of an element
if (type2.Eq(0))
if (type.Eq(0))
{
pStack->SetError(CBotErrNoTerminator, p);
return false;
}
if (pp[0] == '~' || pp == GetName()) // bad variable name
{
pStack->SetError(CBotErrNoVar, varToken);
return false;
}
if (!bSecond && CheckVar(pp)) // variable already exists
{
pStack->SetError(CBotErrRedefVar, varToken);
return false;
}
CBotInstr* limites = nullptr;
while ( IsOfType( p, ID_OPBRK ) ) // an array
{
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
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;
}
CBotInstr* i = nullptr;
if ( IsOfType(p, ID_ASS ) )
{

View File

@ -221,6 +221,13 @@ public:
*/
CBotVar* GetItemRef(int nIdent);
/*!
* \brief Check whether a variable is already defined in a class
* \param name Name of the variable
* \return True if a variable is defined in the class
*/
bool CheckVar(const std::string &name);
/*!
* \brief CompileMethode Compiles a method associated with an instance of
* class the method can be declared by the user or AddFunction.

View File

@ -237,6 +237,7 @@ enum CBotError : int
CBotErrNoPublic = 5042, //!< missing word "public"
CBotErrNoExpression = 5043, //!< expression expected after =
CBotErrAmbiguousCall = 5044, //!< ambiguous call to overloaded function
CBotErrFuncNotVoid = 5045, //!< function needs return type "void"
// Runtime errors
CBotErrZeroDiv = 6000, //!< division by zero

View File

@ -165,6 +165,7 @@ CBotFunction* CBotFunction::Compile(CBotToken* &p, CBotCStack* pStack, CBotFunct
if ( IsOfType(p, ID_NOT) )
{
CBotToken d(std::string("~") + p->GetString());
d.SetPos(pp->GetStart(), p->GetEnd());
func->m_token = d;
}
@ -268,6 +269,7 @@ CBotFunction* CBotFunction::Compile1(CBotToken* &p, CBotCStack* pStack, CBotClas
if ( IsOfType(p, ID_NOT) )
{
CBotToken d(std::string("~") + p->GetString());
d.SetPos(pp->GetStart(), p->GetEnd());
func->m_token = d;
}
@ -289,10 +291,40 @@ CBotFunction* CBotFunction::Compile1(CBotToken* &p, CBotCStack* pStack, CBotClas
if (!IsOfType(p, TokenTypVar)) goto bad;
}
func->m_param = CBotDefParam::Compile(p, pStk );
CBotToken* openPar = p;
func->m_param = CBotDefParam::Compile(p, pStk); // compile parameters
if (pStk->IsOk() && pClass != nullptr) // method in a class
{
// check if a constructor has return type void
if (func->GetName() == pClass->GetName() && !func->m_retTyp.Eq(CBotTypVoid))
{
pp = &(func->m_retToken);
pStk->SetError(CBotErrFuncNotVoid, pp);
}
if (pStk->IsOk() && pp->GetString() == "~") // destructor
{
// check destructor name
if (func->GetName() != ("~" + pClass->GetName()))
pStk->SetError(CBotErrNoFunc, pp);
// confirm no parameters
if (pStk->IsOk() && func->m_param != nullptr)
pStk->SetError(CBotErrClosePar, openPar->GetNext());
// must return void
if (pStk->IsOk() && !func->m_retTyp.Eq(CBotTypVoid))
{
pp = &(func->m_retToken);
pStk->SetError(CBotErrFuncNotVoid, pp);
}
}
}
if (pStk->IsOk())
{
// looks if the function exists elsewhere
pp = &(func->m_token);
if (( pClass != nullptr || !pStack->CheckCall(pp, func->m_param)) &&
( pClass == nullptr || !pClass->CheckCall(pStack->GetProgram(), func->m_param, pp)) )
{

View File

@ -719,6 +719,7 @@ void InitializeRestext()
stringsCbot[CBot::CBotErrNoPublic] = TR("Public required");
stringsCbot[CBot::CBotErrNoExpression] = TR("Expression expected after =");
stringsCbot[CBot::CBotErrAmbiguousCall] = TR("Ambiguous call to overloaded function");
stringsCbot[CBot::CBotErrFuncNotVoid] = TR("Function needs return type \"void\"");
stringsCbot[CBot::CBotErrZeroDiv] = TR("Dividing by zero");
stringsCbot[CBot::CBotErrNotInit] = TR("Variable not initialized");

View File

@ -867,14 +867,13 @@ TEST_F(CBotUT, ClassNullPointer)
);
}
// TODO: This doesn't work
TEST_F(CBotUT, DISABLED_ClassDestructorNaming)
TEST_F(CBotUT, ClassDestructorNaming)
{
ExecuteTest(
"public class TestClass {\n"
" public void ~SomethingElse() {}\n"
"}\n",
static_cast<CBotError>(-1) // TODO: no error for that
CBotErrNoFunc
);
ExecuteTest(
"public class SomethingElse {\n"
@ -882,7 +881,26 @@ TEST_F(CBotUT, DISABLED_ClassDestructorNaming)
"public class TestClass2 {\n"
" public void ~SomethingElse() {}\n"
"}\n",
static_cast<CBotError>(-1) // TODO: no error for that
CBotErrNoFunc
);
}
TEST_F(CBotUT, ClassDestructorSyntax)
{
ExecuteTest(
"public class TestClass {\n"
" void ~TestClass(int i) {}\n"
"}\n"
"extern void DestructorNoParams() {}\n",
CBotErrClosePar
);
ExecuteTest(
"public class TestClass {\n"
" int ~TestClass() {}\n"
"}\n"
"extern void DestructorReturnTypeVoid() {}\n",
CBotErrFuncNotVoid
);
}
@ -930,6 +948,39 @@ TEST_F(CBotUT, ClassMethodRedefined)
"}\n",
CBotErrRedefFunc
);
ExecuteTest(
"public class TestClass {\n"
" void ~TestClass() {}\n"
" void ~TestClass() {}\n"
"}\n",
CBotErrRedefFunc
);
}
TEST_F(CBotUT, ClassFieldNaming)
{
ExecuteTest(
"public class TestClass {\n"
" int ~i = 1;\n"
"}\n",
CBotErrNoVar
);
ExecuteTest(
"public class TestClass {\n"
" int TestClass = 1;\n"
"}\n",
CBotErrNoVar
);
ExecuteTest(
"public class TestClass {\n"
" int i = 1;\n"
" int i = 2;\n"
"}\n",
CBotErrRedefVar
);
}
TEST_F(CBotUT, ClassRedefinedInDifferentPrograms)