/* * This file is part of the Colobot: Gold Edition source code * Copyright (C) 2001-2021, Daniel Roux, EPSITEC SA & TerranovaTeam * http://epsitec.ch; http://colobot.info; http://github.com/colobot * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://gnu.org/licenses */ #pragma once #include "CBot/CBotDefines.h" #include "CBot/CBotTypResult.h" #include "CBot/CBotVar/CBotVar.h" #include #include #include #include namespace CBot { class CBotCallMethode; class CBotFunction; class CBotProgram; class CBotStack; class CBotDefParam; class CBotToken; class CBotCStack; class CBotExternalCallList; /** * \brief A CBot class definition * * \section Examples Usage examples * * Define class "point": * * \code * CBotClass* classPoint = new CBotClass("CPoint", nullptr); * classPoint->AddItem("x", CBotTypResult(CBotTypFloat)); // add ".x" * classPoint->AddItem("y", CBotTypResult(CBotTypFloat)); // add ".y" * * // This class can be used in CBot like so: * // point position; * // position.x = 12; * // position.y = -13.6 * \endcode * * Define readonly class "object" with members of type "point" and some methods: * \code * CBotClass* classObject = new CBotClass("object", nullptr); * classObject->AddItem("category", CBotTypResult(CBotTypInt), CBotVar::ProtectionType::ReadOnly); * classObject->AddItem("position", CBotTypResult(CBotTypClass, classPoint), CBotVar::ProtectionType::ReadOnly); * classObject->AddFunction("func", rFunc, cFunc); // TODO: Document function format for class methods (different from standard CBotProgram::AddFunction()!) * * // This class can be used in CBot like so: * // object item = radar(Me); * // goto(item.position); * // item.func(); * \endcode * * Define class "robot" derrived from "object": * \code * CBotClass* classRobot = new CBotClass("object", classObject); * classRobot->AddItem("velocity", CBotTypResult(CBotTypClass, classPoint), CBotVar::ProtectionType::ReadOnly); * classRobot->AddFunction("func2", rFunc2, cFunc2); * * // This class can be used in CBot like so: * // robot item = something(); * // goto(item.position); // can still access base class * // item.func(); // can still call base class * // item.func2(); // but also the derrived class * \endcode * * Create instance of the "robot" class: * \code * CBotVar* var = new CBotVar("variableName", classRobot); * \endcode * * Access members of the "point" class: * \code * CBotVar* varX = classInstance->GetItem("x"); * float x = varX->GetValFloat(); * CBotVar* varY = classInstance->GetItem("y"); * float y = varX->GetValFloat(); * * // OR * * CBotVar* var = classInstance->GetItemList(); * float x = var->GetValFloat(); * var->GetNext(); * float y = var->GetValFloat(); * \endcode */ class CBotClass { public: /*! * \brief CBotClass Constructor. Once a class is created, it is known around * CBot intrinsic mode gives a class that is not managed by pointers. * \param name * \param parent * \param bIntrinsic */ CBotClass(const std::string& name, CBotClass* parent, bool bIntrinsic = false); /*! * \brief CBotClass Destructor. */ ~CBotClass( ); /*! * \brief Create * \param name * \param parent * \param intrinsic * \return */ static CBotClass* Create(const std::string& name, CBotClass* parent, bool intrinsic = false); /*! * \brief Add a function that can be called from CBot * \see CBotProgram::AddFunction */ bool AddFunction(const std::string& name, bool rExec(CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception, void* user), CBotTypResult rCompile(CBotVar* pThis, CBotVar*& pVar)); /*! * \brief SetUpdateFunc Defines routine to be called to update the elements * of the class. * \param rUpdate * \return */ bool SetUpdateFunc(void rUpdate(CBotVar* thisVar, void* user)); // /*! * \brief AddItem Adds an element to the class. * \param name * \param type * \param mPrivate * \return */ bool AddItem(std::string name, CBotTypResult type, CBotVar::ProtectionLevel mPrivate = CBotVar::ProtectionLevel::Public); /*! * \brief AddItem Adds an item by passing the pointer to an instance of a * variable the object is taken as is, so do not destroyed. * \param pVar * \return */ bool AddItem(CBotVar* pVar); /*! * \brief GetName Gives the name of the class. * \return */ const std::string& GetName(); /*! * \brief GetParent Gives the parent class (or nullptr). * \return */ CBotClass* GetParent(); /*! * \brief IsChildOf True if a class is derived (Extends) of another. * \param pClass * \return true also if the classes are identical */ bool IsChildOf(CBotClass* pClass); /*! * \brief Find Trouve une classe d'après son nom * \param pToken * \return A class by it's its name. */ static CBotClass* Find(CBotToken* &pToken); /*! * \brief Find * \param name * \return */ static CBotClass* Find(const std::string& name); /*! * \brief GetVar Return the list of variables. * \return */ CBotVar* GetVar(); /*! * \brief GetItem One of the variables according to its name. * \param name * \return */ CBotVar* GetItem(const std::string& name); /*! * \brief GetItemRef * \param nIdent * \return */ 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. * \param name * \param pThis * \param ppParams * \param pStack * \param nIdent * \return */ CBotTypResult CompileMethode(CBotToken* name, CBotVar* pThis, CBotVar** ppParams, CBotCStack* pStack, long &nIdent); /*! * \brief ExecuteMethode Executes a method. * \param nIdent * \param name * \param pThis * \param ppParams * \param pResultType * \param pStack * \param pToken * \return */ bool ExecuteMethode(long &nIdent, CBotVar* pThis, CBotVar** ppParams, CBotTypResult pResultType, CBotStack*&pStack, CBotToken* pToken); /*! * \brief RestoreMethode Restored the execution stack. * \param nIdent * \param name * \param pThis * \param ppParams * \param pStack */ void RestoreMethode(long &nIdent, CBotToken* name, CBotVar* pThis, CBotVar** ppParams, CBotStack*&pStack); /*! * \brief Compile Compiles a class declared by the user. * \param p * \param pStack * \return */ static CBotClass* Compile(CBotToken* &p, CBotCStack* pStack); /*! * \brief Pre-compile a new class * \param p[in, out] Pointer to first token of the class, will be updated to point to first token after the class definition * \param pStack Compile stack * * This function is used to find the beginning and end of class definition. * * If any errors in the code are detected, this function will set the error on compile stack and return nullptr. * * \return Precompiled class, or nullptr in case of error */ 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 pClassList List of classes * \param pStack */ static void DefineClasses(std::list pClassList, CBotCStack* pStack); /*! * \brief Get the list of user-defined methods in this class. * \return List of methods, can be empty. */ const std::list& GetFunctions() const; /*! * \brief CompileDefItem * \param p * \param pStack * \param bSecond * \return */ bool CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond); /*! * \brief IsIntrinsic * \return */ bool IsIntrinsic(); /*! * \brief Purge */ void Purge(); /*! * \brief Free */ static void ClearPublic(); /*! * \brief Save all static variables from each public class * \param ostr Output stream * \return true on success */ static bool SaveStaticState(std::ostream &ostr); /*! * \brief Restore all static variables in each public class * \param istr Input stream * \return true on success */ static bool RestoreStaticState(std::istream &istr); /** * \brief Request a lock on this class (for "synchronized" keyword) * \param prog Program that requests the lock * \return true if lock was acquired, false if the lock is already taken */ bool Lock(CBotProgram* prog); /** * \brief Release the lock acquired in Lock() * If you call Lock() multiple times for the same program, you have to call Unlock() multiple times too */ void Unlock(); /** * \brief Release all locks in all classes held by this program * \param prog Program to release the locks from */ static void FreeLock(CBotProgram* prog); /*! * \brief CheckCall Test if a procedure name is already defined somewhere. * \param program * \param pToken * \param pParam * \return */ bool CheckCall(CBotProgram* program, CBotDefParam* pParam, CBotToken*& pToken); void Update(CBotVar* var, void* user); private: //! List of all public classes static std::set m_publicClasses; //! true if this class is fully compiled, false if only precompiled bool m_IsDef; //! Name of this class std::string m_name; //! Parent class CBotClass* m_parent; //! Number of variables in the chain int m_nbVar; //! Intrinsic class bool m_bIntrinsic; //! Linked list of all class fields CBotVar* m_pVar; //! Linked list of all class external calls CBotExternalCallList* m_externalMethods; //! List of all class methods std::list 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 std::deque m_lockProg{}; }; } // namespace CBot