From a5909ac4de88ad6f1a4bf7b35ea258a758a4c32c Mon Sep 17 00:00:00 2001 From: melex750 Date: Wed, 15 Nov 2017 16:22:00 -0500 Subject: [PATCH] Add private and protected keywords for methods fixes #854 fixes #882 --- src/CBot/CBotInstr/CBotFunction.cpp | 73 +++++++++++++--- src/CBot/CBotInstr/CBotFunction.h | 16 ++++ test/unit/CBot/CBot_test.cpp | 129 ++++++++++++++++++++++++++++ 3 files changed, 208 insertions(+), 10 deletions(-) diff --git a/src/CBot/CBotInstr/CBotFunction.cpp b/src/CBot/CBotInstr/CBotFunction.cpp index 5004cd66..5028fa1b 100644 --- a/src/CBot/CBotInstr/CBotFunction.cpp +++ b/src/CBot/CBotInstr/CBotFunction.cpp @@ -76,6 +76,18 @@ bool CBotFunction::IsPublic() return m_bPublic; } +//////////////////////////////////////////////////////////////////////////////// +bool CBotFunction::IsProtected() +{ + return m_bProtect; +} + +//////////////////////////////////////////////////////////////////////////////// +bool CBotFunction::IsPrivate() +{ + return m_bPrivate; +} + //////////////////////////////////////////////////////////////////////////////// bool CBotFunction::IsExtern() { @@ -135,13 +147,11 @@ CBotFunction* CBotFunction::Compile(CBotToken* &p, CBotCStack* pStack, CBotFunct while (true) { - if ( IsOfType(p, ID_PUBLIC) ) - { - func->m_bPublic = true; - continue; - } + if (IsOfType(p, ID_PRIVATE)) break; + if (IsOfType(p, ID_PROTECTED)) break; + if (IsOfType(p, ID_PUBLIC)) continue; pp = p; - if ( IsOfType(p, ID_EXTERN) ) + if (IsOfType(p, ID_EXTERN)) { func->m_extern = *pp; // for the position of the word "extern" func->m_bExtern = true; @@ -249,14 +259,30 @@ CBotFunction* CBotFunction::Compile1(CBotToken* &p, CBotCStack* pStack, CBotClas CBotCStack* pStk = pStack->TokenStack(p, true); + CBotToken* pPriv = p; + while (true) { - if ( IsOfType(p, ID_PUBLIC) ) + if (!func->m_bPublic) // don't repeat 'public' { - // func->m_bPublic = true; // will be done in two passes - continue; + pPriv = p; + if (IsOfType(p, ID_PRIVATE)) + { + func->m_bPrivate = true; + break; + } + if (IsOfType(p, ID_PROTECTED)) + { + func->m_bProtect = true; + break; + } + if (IsOfType(p, ID_PUBLIC)) + { + func->m_bPublic = true; + continue; + } } - if ( IsOfType(p, ID_EXTERN) ) + if (!func->m_bExtern && IsOfType(p, ID_EXTERN)) { func->m_bExtern = true; continue; @@ -292,6 +318,14 @@ CBotFunction* CBotFunction::Compile1(CBotToken* &p, CBotCStack* pStack, CBotClas if (!IsOfType(p, TokenTypVar)) goto bad; } + else if (pClass == nullptr) // not method in a class ? + { + if (func->m_bPrivate || func->m_bProtect) // not allowed for regular functions + { + pStk->SetError(CBotErrNoType, pPriv); + goto bad; + } + } CBotToken* openPar = p; func->m_param = CBotDefParam::Compile(p, pStk); // compile parameters @@ -877,6 +911,25 @@ CBotTypResult CBotFunction::CompileMethodCall(const std::string& name, CBotVar** if (pt != nullptr) { + CBotToken token("this"); + CBotVar* pThis = pStack->FindVar(token); // for 'this' context + + if (pThis == nullptr || pThis->GetType() != CBotTypPointer) // called from inside a function + { + if (pt->IsPrivate() || pt->IsProtected()) + type.SetType(CBotErrPrivate); + } + else // called from inside a method + { + CBotClass* thisClass = pThis->GetClass(); // current class + CBotClass* funcClass = CBotClass::Find(pt->m_MasterClass); // class of the method + + if (pt->IsPrivate() && thisClass != funcClass) + type.SetType(CBotErrPrivate); + + if (pt->IsProtected() && !thisClass->IsChildOf(funcClass)) + type.SetType(CBotErrPrivate); + } } return type; diff --git a/src/CBot/CBotInstr/CBotFunction.h b/src/CBot/CBotInstr/CBotFunction.h index da8b0b2d..29c2b15d 100644 --- a/src/CBot/CBotInstr/CBotFunction.h +++ b/src/CBot/CBotInstr/CBotFunction.h @@ -283,6 +283,18 @@ public: */ bool IsPublic(); + /*! + * \brief Check if a method is protected. + * \return true if a method was compiled with "protected" keyword. + */ + bool IsProtected(); + + /*! + * \brief Check if a method is private. + * \return true if a method was compiled with "private" keyword. + */ + bool IsPrivate(); + /*! * \brief IsExtern * \return @@ -328,6 +340,10 @@ private: CBotTypResult m_retTyp; //! Public function. bool m_bPublic; + //! Protected method. + bool m_bProtect = false; + //! Private method. + bool m_bPrivate = false; //! Extern function. bool m_bExtern; //! Name of the class we are part of diff --git a/test/unit/CBot/CBot_test.cpp b/test/unit/CBot/CBot_test.cpp index 701dbf2f..8d115ff6 100644 --- a/test/unit/CBot/CBot_test.cpp +++ b/test/unit/CBot/CBot_test.cpp @@ -3068,3 +3068,132 @@ TEST_F(CBotUT, ClassInheritanceTestThisOutOfClass) "}\n" ); } + +TEST_F(CBotUT, ClassTestProtectedMethod) +{ + auto publicProgram = ExecuteTest( + "public class BaseClass {\n" + " protected bool BaseClassProtected() {\n" + " return true;\n" + " }\n" + " bool NoErrorProtectedSameClass() {\n" + " BaseClass b();\n" + " ASSERT(true == b.BaseClassProtected());\n" + " return BaseClassProtected();\n" + " }\n" + "}\n" + "extern void Test() {\n" + " BaseClass b();\n" + " ASSERT(true == b.NoErrorProtectedSameClass());\n" + "}\n" + ); + + ExecuteTest( + "public class SubClass extends BaseClass {\n" + " bool NoErrorProtectedSubClass() {\n" + " ASSERT(true == BaseClassProtected());\n" + " ASSERT(true == this.BaseClassProtected());\n" + " ASSERT(true == super.BaseClassProtected());\n" + " return true;\n" + " }\n" + "}\n" + "extern void TestNoErrorProtected() {\n" + " SubClass s();\n" + " ASSERT(true == s.NoErrorProtectedSubClass());\n" + "}\n" + ); + + ExecuteTest( + "extern void TestErrorProtected_1() {\n" + " BaseClass b();\n" + " b.BaseClassProtected();\n" + "}\n", + CBotErrPrivate + ); + + ExecuteTest( + "public class SubClass extends BaseClass {}\n" + "\n" + "extern void TestErrorProtected_2() {\n" + " SubClass s();\n" + " s.BaseClassProtected();\n" + "}\n", + CBotErrPrivate + ); + + ExecuteTest( + "public class SomeOtherClass {\n" + " void testErrorProtected() {\n" + " BaseClass b();\n" + " b.BaseClassProtected();\n" + " }\n" + "}\n", + CBotErrPrivate + ); +} + +TEST_F(CBotUT, ClassTestPrivateMethod) +{ + auto publicProgram = ExecuteTest( + "public class BaseClass {\n" + " private bool BaseClassPrivate() {\n" + " return true;\n" + " }\n" + " bool NoErrorPrivateSameClass() {\n" + " BaseClass b();\n" + " ASSERT(true == b.BaseClassPrivate());\n" + " return BaseClassPrivate();\n" + " }\n" + "}\n" + "extern void Test() {\n" + " BaseClass b();\n" + " ASSERT(true == b.NoErrorPrivateSameClass());\n" + "}\n" + ); + + ExecuteTest( + "public class SubClass extends BaseClass {\n" + " void ErrorPrivateThis() {\n" + " this.BaseClassPrivate();\n" + " }\n" + "}\n", + CBotErrPrivate + ); + + ExecuteTest( + "public class SubClass extends BaseClass {\n" + " void ErrorPrivateSuper() {\n" + " super.BaseClassPrivate();\n" + " }\n" + "}\n", + CBotErrPrivate + ); + + ExecuteTest( + "extern void TestErrorPrivate_1() {\n" + " BaseClass b();\n" + " b.BaseClassPrivate();\n" + "}\n", + CBotErrPrivate + ); + + ExecuteTest( + "public class SubClass extends BaseClass {}\n" + "\n" + "extern void TestErrorPrivate_2() {\n" + " SubClass s();\n" + " s.BaseClassPrivate();\n" + "}\n", + CBotErrPrivate + ); + + ExecuteTest( + "public class SomeOtherClass {\n" + " void ErrorPrivate() {\n" + " BaseClass b();\n" + " b.BaseClassPrivate();\n" + " }\n" + "}\n", + CBotErrPrivate + ); +}