[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