Allow circular references from different classes (#814)
Conflicts: test/unit/CBot/CBot_test.cppdev-new-models
commit
d411c5ebc0
|
@ -509,16 +509,25 @@ CBotClass* CBotClass::Compile1(CBotToken* &p, CBotCStack* pStack)
|
|||
classe->Purge(); // empty the old definitions // TODO: Doesn't this remove all classes of the current program?
|
||||
classe->m_IsDef = false; // current definition
|
||||
|
||||
classe->m_pOpenblk = p;
|
||||
|
||||
if ( !IsOfType( p, ID_OPBLK) )
|
||||
{
|
||||
pStack->SetError(CBotErrOpenBlock, p);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
while ( pStack->IsOk() && !IsOfType( p, ID_CLBLK ) )
|
||||
int level = 1;
|
||||
do // skip over the definition
|
||||
{
|
||||
classe->CompileDefItem(p, pStack, false);
|
||||
int type = p->GetType();
|
||||
p = p->GetNext();
|
||||
if (type == ID_OPBLK) level++;
|
||||
if (type == ID_CLBLK) level--;
|
||||
}
|
||||
while (level > 0 && p != nullptr);
|
||||
|
||||
if (level > 0) pStack->SetError(CBotErrCloseBlock, classe->m_pOpenblk);
|
||||
|
||||
if (pStack->IsOk()) return classe;
|
||||
}
|
||||
|
@ -526,6 +535,26 @@ CBotClass* CBotClass::Compile1(CBotToken* &p, CBotCStack* pStack)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void CBotClass::DefineClasses(CBotClass* pClass, CBotCStack* pStack)
|
||||
{
|
||||
while (pClass != nullptr)
|
||||
{
|
||||
CBotClass* pParent = pClass->m_parent;
|
||||
pClass->m_nbVar = (pParent == nullptr) ? 0 : pParent->m_nbVar;
|
||||
CBotToken* p = pClass->m_pOpenblk->GetNext();
|
||||
|
||||
while (pStack->IsOk() && !IsOfType(p, ID_CLBLK))
|
||||
{
|
||||
pClass->CompileDefItem(p, pStack, false);
|
||||
}
|
||||
|
||||
if (!pStack->IsOk()) return;
|
||||
|
||||
pClass = pClass->GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
|
||||
{
|
||||
|
|
|
@ -291,6 +291,14 @@ public:
|
|||
static CBotClass* Compile1(CBotToken* &p,
|
||||
CBotCStack* pStack);
|
||||
|
||||
/*!
|
||||
* \brief DefineClasses Calls CompileDefItem for each class in a list
|
||||
* of classes, defining fields and pre-compiling methods.
|
||||
* \param pClass List of classes
|
||||
* \param pStack
|
||||
*/
|
||||
static void DefineClasses(CBotClass* pClass, CBotCStack* pStack);
|
||||
|
||||
/*!
|
||||
* \brief CompileDefItem
|
||||
* \param p
|
||||
|
@ -385,6 +393,8 @@ private:
|
|||
CBotFunction* m_pMethod;
|
||||
void (*m_rUpdate)(CBotVar* thisVar, void* user);
|
||||
|
||||
CBotToken* m_pOpenblk;
|
||||
|
||||
//! How many times the program currently holding the lock called Lock()
|
||||
int m_lockCurrentCount = 0;
|
||||
//! Programs waiting for lock. m_lockProg[0] is the program currently holding the lock, if any
|
||||
|
|
|
@ -99,6 +99,10 @@ bool CBotProgram::Compile(const std::string& program, std::vector<std::string>&
|
|||
else m_functions->AddNext(next);
|
||||
}
|
||||
}
|
||||
|
||||
// Define fields and pre-compile methods for each class in this program
|
||||
if (pStack->IsOk()) CBotClass::DefineClasses(m_classes, pStack.get());
|
||||
|
||||
if ( !pStack->IsOk() )
|
||||
{
|
||||
m_error = pStack->GetError(m_errorStart, m_errorEnd);
|
||||
|
|
|
@ -1283,6 +1283,41 @@ TEST_F(CBotUT, ClassInheritanceTestThis)
|
|||
);
|
||||
}
|
||||
|
||||
TEST_F(CBotUT, ClassCompileCircularReference_Issue433)
|
||||
{
|
||||
ExecuteTest(
|
||||
"public class OtherClass {\n"
|
||||
" TestClass testclass;\n"
|
||||
"}\n"
|
||||
"public class TestClass {\n"
|
||||
" int test;\n"
|
||||
" OtherClass otherclass;\n"
|
||||
"}\n"
|
||||
"extern void TestCompileCircularReference()\n"
|
||||
"{\n"
|
||||
" TestClass t();\n"
|
||||
"}\n"
|
||||
);
|
||||
}
|
||||
|
||||
TEST_F(CBotUT, ClassTestClassDefinedAfterReference)
|
||||
{
|
||||
ExecuteTest(
|
||||
"public class OtherClass {\n"
|
||||
" TestClass testclass = new TestClass();\n"
|
||||
"}\n"
|
||||
"public class TestClass {\n"
|
||||
" int test = 246;\n"
|
||||
"}\n"
|
||||
"extern void TestDefinedAfterReference()\n"
|
||||
"{\n"
|
||||
" OtherClass o();\n"
|
||||
" TestClass t = o.testclass;\n"
|
||||
" ASSERT(t.test == 246);\n"
|
||||
"}\n"
|
||||
);
|
||||
}
|
||||
|
||||
TEST_F(CBotUT, String)
|
||||
{
|
||||
ExecuteTest(
|
||||
|
|
Loading…
Reference in New Issue