[colobot] 35/74: Add method chaining for class constructor calls
Didier Raboud
odyx at moszumanska.debian.org
Mon Nov 7 07:50:02 UTC 2016
This is an automated email from the git hooks/post-receive script.
odyx pushed a commit to branch debian/master
in repository colobot.
commit 3146d4ef358bc06767013993ccb18487a639eb65
Author: melex750 <melex750 at users.noreply.github.com>
Date: Sun Aug 14 16:56:17 2016 -0400
Add method chaining for class constructor calls
---
src/CBot/CBotInstr/CBotDefClass.cpp | 43 +++++++++++++++++++++++++++++++++
src/CBot/CBotInstr/CBotDefClass.h | 3 +++
src/CBot/CBotInstr/CBotExprRetVar.cpp | 17 +++++++------
src/CBot/CBotInstr/CBotExprRetVar.h | 2 +-
src/CBot/CBotInstr/CBotInstrMethode.cpp | 7 +++---
src/CBot/CBotInstr/CBotInstrMethode.h | 3 ++-
src/CBot/CBotInstr/CBotNew.cpp | 43 ++++++++++++++++++++++++++++++++-
src/CBot/CBotInstr/CBotNew.h | 3 +++
test/unit/CBot/CBot_test.cpp | 35 +++++++++++++++++++++++++++
9 files changed, 143 insertions(+), 13 deletions(-)
diff --git a/src/CBot/CBotInstr/CBotDefClass.cpp b/src/CBot/CBotInstr/CBotDefClass.cpp
index bfd0ded..cd73d9c 100644
--- a/src/CBot/CBotInstr/CBotDefClass.cpp
+++ b/src/CBot/CBotInstr/CBotDefClass.cpp
@@ -19,6 +19,7 @@
#include "CBot/CBotInstr/CBotDefClass.h"
+#include "CBot/CBotInstr/CBotExprRetVar.h"
#include "CBot/CBotInstr/CBotInstrUtils.h"
#include "CBot/CBotInstr/CBotLeftExprVar.h"
@@ -44,6 +45,7 @@ CBotDefClass::CBotDefClass()
m_expr = nullptr;
m_hasParams = false;
m_nMethodeIdent = 0;
+ m_exprRetVar = nullptr;
}
////////////////////////////////////////////////////////////////////////////////
@@ -150,6 +152,16 @@ CBotInstr* CBotDefClass::Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* p
goto error;
}
+ pStk->SetCopyVar(var);
+ // chained method ?
+ if (nullptr != (inst->m_exprRetVar = CBotExprRetVar::Compile(p, pStk, true)))
+ {
+ inst->m_exprRetVar->SetToken(vartoken);
+ delete pStk->TokenStack();
+ }
+ pStk->SetVar(nullptr);
+
+ if ( !pStk->IsOk() ) goto error;
}
if (IsOfType(p, ID_ASS)) // with a assignment?
@@ -232,6 +244,19 @@ bool CBotDefClass::Execute(CBotStack* &pj)
CBotStack* pile = pj->AddStack(this);//essential for SetState()
// if ( pile == EOX ) return true;
+ if (m_exprRetVar != nullptr) // Class c().method();
+ {
+ if (pile->IfStep()) return false;
+ if (pile->GetState() == 4)
+ {
+ CBotStack* pile3 = pile->AddStack();
+ if (!m_exprRetVar->Execute(pile3)) return false;
+ pile3->SetVar(nullptr);
+ pile->Return(pile3); // release pile3 stack
+ pile->SetState(5);
+ }
+ }
+
CBotToken* pt = &m_token;
CBotClass* pClass = CBotClass::Find(pt);
@@ -363,6 +388,14 @@ bool CBotDefClass::Execute(CBotStack* &pj)
pile->SetState(3); // finished this part
}
+ if (m_exprRetVar != nullptr && pile->GetState() == 3) // Class c().method();
+ {
+ CBotStack* pile3 = pile->AddStack();
+ pile3->SetCopyVar(pThis);
+ pile->SetState(4);
+ return false; // go back to the top ^^^
+ }
+
if ( pile->IfStep() ) return false;
if ( m_next2b != nullptr &&
@@ -387,6 +420,16 @@ void CBotDefClass::RestoreState(CBotStack* &pj, bool bMain)
pThis->SetUniqNum((static_cast<CBotLeftExprVar*>(m_var))->m_nIdent); // its attribute a unique number
}
+ if (m_exprRetVar != nullptr) // Class c().method();
+ {
+ if (pile->GetState() == 4)
+ {
+ CBotStack* pile3 = pile->RestoreStack();
+ m_exprRetVar->RestoreState(pile3, bMain);
+ return;
+ }
+ }
+
CBotToken* pt = &m_token;
CBotClass* pClass = CBotClass::Find(pt);
bool bIntrincic = pClass->IsIntrinsic();
diff --git a/src/CBot/CBotInstr/CBotDefClass.h b/src/CBot/CBotInstr/CBotDefClass.h
index 82c5952..abad795 100644
--- a/src/CBot/CBotInstr/CBotDefClass.h
+++ b/src/CBot/CBotInstr/CBotDefClass.h
@@ -85,6 +85,9 @@ private:
//! Constructor method unique identifier
long m_nMethodeIdent;
+ //! Instruction to chain method calls after constructor
+ CBotInstr* m_exprRetVar;
+
};
} // namespace CBot
diff --git a/src/CBot/CBotInstr/CBotExprRetVar.cpp b/src/CBot/CBotInstr/CBotExprRetVar.cpp
index 9a1eeb7..96ff03c 100644
--- a/src/CBot/CBotInstr/CBotExprRetVar.cpp
+++ b/src/CBot/CBotInstr/CBotExprRetVar.cpp
@@ -41,17 +41,13 @@ CBotExprRetVar::~CBotExprRetVar()
}
////////////////////////////////////////////////////////////////////////////////
-CBotInstr* CBotExprRetVar::Compile(CBotToken*& p, CBotCStack* pStack)
+CBotInstr* CBotExprRetVar::Compile(CBotToken*& p, CBotCStack* pStack, bool bMethodsOnly)
{
if (p->GetType() == ID_DOT)
{
CBotVar* var = pStack->GetVar();
- if (var == nullptr)
- {
- pStack->SetError(CBotErrNoTerminator, p->GetStart());
- return nullptr;
- }
+ if (var == nullptr) return nullptr;
CBotCStack* pStk = pStack->TokenStack();
CBotInstr* inst = new CBotExprRetVar();
@@ -61,6 +57,8 @@ CBotInstr* CBotExprRetVar::Compile(CBotToken*& p, CBotCStack* pStack)
pStk->SetStartError(p->GetStart());
if (var->GetType() == CBotTypArrayPointer)
{
+ if (bMethodsOnly) goto err;
+
if (IsOfType( p, ID_OPBRK ))
{
CBotIndexExpr* i = new CBotIndexExpr();
@@ -92,11 +90,16 @@ CBotInstr* CBotExprRetVar::Compile(CBotToken*& p, CBotCStack* pStack)
{
if (p->GetNext()->GetType() == ID_OPENPAR)
{
- CBotInstr* i = CBotInstrMethode::Compile(p, pStk, var);
+ CBotInstr* i = CBotInstrMethode::Compile(p, pStk, var, bMethodsOnly);
if (!pStk->IsOk()) goto err;
inst->AddNext3(i);
return pStack->Return(inst, pStk);
}
+ else if (bMethodsOnly)
+ {
+ p = p->GetPrev();
+ goto err;
+ }
else
{
CBotFieldExpr* i = new CBotFieldExpr();
diff --git a/src/CBot/CBotInstr/CBotExprRetVar.h b/src/CBot/CBotInstr/CBotExprRetVar.h
index a1c37f5..2c8321e 100644
--- a/src/CBot/CBotInstr/CBotExprRetVar.h
+++ b/src/CBot/CBotInstr/CBotExprRetVar.h
@@ -36,7 +36,7 @@ public:
CBotExprRetVar();
~CBotExprRetVar();
- static CBotInstr* Compile(CBotToken*& p, CBotCStack* pStack);
+ static CBotInstr* Compile(CBotToken*& p, CBotCStack* pStack, bool bMethodsOnly = false);
/*!
* \brief Execute
diff --git a/src/CBot/CBotInstr/CBotInstrMethode.cpp b/src/CBot/CBotInstr/CBotInstrMethode.cpp
index cbc3a60..bf4ec41 100644
--- a/src/CBot/CBotInstr/CBotInstrMethode.cpp
+++ b/src/CBot/CBotInstr/CBotInstrMethode.cpp
@@ -46,7 +46,7 @@ CBotInstrMethode::~CBotInstrMethode()
}
////////////////////////////////////////////////////////////////////////////////
-CBotInstr* CBotInstrMethode::Compile(CBotToken* &p, CBotCStack* pStack, CBotVar* var)
+CBotInstr* CBotInstrMethode::Compile(CBotToken* &p, CBotCStack* pStack, CBotVar* var, bool bMethodChain)
{
CBotInstrMethode* inst = new CBotInstrMethode();
inst->SetToken(p); // corresponding token
@@ -90,9 +90,10 @@ CBotInstr* CBotInstrMethode::Compile(CBotToken* &p, CBotCStack* pStack, CBotVar*
}
else pStack->SetVar(nullptr);
- if (nullptr != (inst->m_exprRetVar = CBotExprRetVar::Compile(p, pStack)))
+ pp = p;
+ if (nullptr != (inst->m_exprRetVar = CBotExprRetVar::Compile(p, pStack, bMethodChain)))
{
- inst->m_exprRetVar->SetToken(&inst->m_token);
+ inst->m_exprRetVar->SetToken(pp);
delete pStack->TokenStack();
}
diff --git a/src/CBot/CBotInstr/CBotInstrMethode.h b/src/CBot/CBotInstr/CBotInstrMethode.h
index a74a49a..502dcf4 100644
--- a/src/CBot/CBotInstr/CBotInstrMethode.h
+++ b/src/CBot/CBotInstr/CBotInstrMethode.h
@@ -38,9 +38,10 @@ public:
* \param p
* \param pStack
* \param pVar
+ * \param bMethodChain If true, allows chaining methods only
* \return
*/
- static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, CBotVar* pVar);
+ static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, CBotVar* pVar, bool bMethodChain = false);
/*!
* \brief Execute
diff --git a/src/CBot/CBotInstr/CBotNew.cpp b/src/CBot/CBotInstr/CBotNew.cpp
index a302b39..e7d973c 100644
--- a/src/CBot/CBotInstr/CBotNew.cpp
+++ b/src/CBot/CBotInstr/CBotNew.cpp
@@ -24,6 +24,7 @@
#include "CBot/CBotCStack.h"
#include "CBot/CBotClass.h"
+#include "CBot/CBotInstr/CBotExprRetVar.h"
#include "CBot/CBotInstr/CBotInstrUtils.h"
#include "CBot/CBotVar/CBotVar.h"
@@ -105,7 +106,17 @@ CBotInstr* CBotNew::Compile(CBotToken* &p, CBotCStack* pStack)
// makes pointer to the object on the stack
pStk->SetVar(pVar);
- return pStack->Return(inst, pStk);
+
+ pp = p;
+ // chained method ?
+ if (nullptr != (inst->m_exprRetVar = CBotExprRetVar::Compile(p, pStk, true)))
+ {
+ inst->m_exprRetVar->SetToken(pp);
+ delete pStk->TokenStack();
+ }
+
+ if (pStack->IsOk())
+ return pStack->Return(inst, pStk);
}
error:
delete inst;
@@ -117,6 +128,16 @@ bool CBotNew::Execute(CBotStack* &pj)
{
CBotStack* pile = pj->AddStack(this); //main stack
+ if (m_exprRetVar != nullptr) // new Class().method()
+ {
+ if (pile->GetState() == 2)
+ {
+ CBotStack* pile3 = pile->AddStack();
+ if (!m_exprRetVar->Execute(pile3)) return false;
+ return pj->Return(pile3);
+ }
+ }
+
if (pile->IfStep()) return false;
CBotStack* pile1 = pj->AddStack2(); //secondary stack
@@ -186,6 +207,16 @@ bool CBotNew::Execute(CBotStack* &pj)
pThis->ConstructorSet(); // indicates that the constructor has been called
}
+ if (m_exprRetVar != nullptr) // new Class().method()
+ {
+ pile->AddStack()->Delete(); // release pile2 stack
+ CBotStack* pile3 = pile->AddStack(); // add new stack
+ pile3->SetCopyVar(pThis); // copy the pointer (from pile1)
+ pile1->Delete(); // release secondary stack(pile1)
+ pile->SetState(2);
+ return false; // go back to the top ^^^
+ }
+
return pj->Return(pile1); // passes below
}
@@ -197,6 +228,16 @@ void CBotNew::RestoreState(CBotStack* &pj, bool bMain)
CBotStack* pile = pj->RestoreStack(this); //primary stack
if (pile == nullptr) return;
+ if (m_exprRetVar != nullptr) // new Class().method()
+ {
+ if (pile->GetState() == 2)
+ {
+ CBotStack* pile3 = pile->RestoreStack();
+ m_exprRetVar->RestoreState(pile3, bMain);
+ return;
+ }
+ }
+
CBotStack* pile1 = pj->AddStack2(); //secondary stack
CBotToken* pt = &m_vartoken;
diff --git a/src/CBot/CBotInstr/CBotNew.h b/src/CBot/CBotInstr/CBotNew.h
index 76cf3e9..c69da3a 100644
--- a/src/CBot/CBotInstr/CBotNew.h
+++ b/src/CBot/CBotInstr/CBotNew.h
@@ -66,6 +66,9 @@ private:
long m_nMethodeIdent;
CBotToken m_vartoken;
+ //! Instruction to chain method calls after constructor
+ CBotInstr* m_exprRetVar;
+
};
} // namespace CBot
diff --git a/test/unit/CBot/CBot_test.cpp b/test/unit/CBot/CBot_test.cpp
index da9fd95..071abb9 100644
--- a/test/unit/CBot/CBot_test.cpp
+++ b/test/unit/CBot/CBot_test.cpp
@@ -1751,3 +1751,38 @@ TEST_F(CBotUT, InstrCallAccessMemberNewObjectDestructor)
"}\n"
);
}
+
+TEST_F(CBotUT, ClassConstructorMethodChain)
+{
+ ExecuteTest(
+ "public class TestClass {\n"
+ " int a = 123;\n"
+ " int b = 246;\n"
+ " TestClass testSetA(int x) { a = x; return this; }\n"
+ " TestClass testSetB(int y) { b = y; return this; }\n"
+ "}\n"
+ "extern void ConstructorMethodChain() {\n"
+ " TestClass tc().testSetA(111).testSetB(222);\n"
+ " ASSERT(tc.a == 111);\n"
+ " ASSERT(tc.b == 222);\n"
+ "}\n"
+ );
+}
+
+TEST_F(CBotUT, ClassNewConstructorMethodChain)
+{
+ ExecuteTest(
+ "public class TestClass {\n"
+ " int a = 123;\n"
+ " int b = 246;\n"
+ " TestClass testSetA(int x) { a = x; return this; }\n"
+ " TestClass testSetB(int y) { b = y; return this; }\n"
+ "}\n"
+ "extern void NewConstructorMethodChain() {\n"
+ " TestClass tc;\n"
+ " tc = new TestClass().testSetA(111).testSetB(222);\n"
+ " ASSERT(tc.a == 111);\n"
+ " ASSERT(tc.b == 222);\n"
+ "}\n"
+ );
+}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/colobot.git
More information about the Pkg-games-commits
mailing list