From eedf8dacea348bd6273736b5bf8d84c0b87182bc Mon Sep 17 00:00:00 2001 From: krzys-h Date: Mon, 21 Dec 2015 21:35:20 +0100 Subject: [PATCH] Documentation for CBotProgram; some CBotError refactoring --- src/CBot/CBotCall.cpp | 6 +- src/CBot/CBotCallMethode.cpp | 8 +- src/CBot/CBotInstr/CBotExprVar.cpp | 2 +- src/CBot/CBotInstr/CBotFunction.cpp | 2 +- src/CBot/CBotInstr/CBotLeftExpr.cpp | 2 +- src/CBot/CBotInstr/CBotThrow.cpp | 2 +- src/CBot/CBotInstr/CBotTry.cpp | 6 +- src/CBot/CBotInstr/CBotTwoOpExpr.cpp | 4 +- src/CBot/CBotProgram.cpp | 70 ++--- src/CBot/CBotProgram.h | 397 +++++++++++++++------------ src/CBot/CBotStack.cpp | 20 +- src/CBot/CBotStack.h | 9 +- src/CBot/CBotTypResult.h | 6 + src/CBot/CBotVar/CBotVar.cpp | 8 +- src/CBot/CBotVar/CBotVar.h | 5 +- src/CBot/CBotVar/CBotVarClass.cpp | 3 +- src/CBot/CBotVar/CBotVarFloat.cpp | 8 +- src/CBot/CBotVar/CBotVarFloat.h | 5 +- src/CBot/CBotVar/CBotVarInt.cpp | 8 +- src/CBot/CBotVar/CBotVarInt.h | 5 +- src/CBot/README.txt | 4 + src/script/script.cpp | 10 +- src/script/script.h | 2 +- test/cbot/console/main.cpp | 6 +- 24 files changed, 323 insertions(+), 275 deletions(-) create mode 100644 src/CBot/README.txt diff --git a/src/CBot/CBotCall.cpp b/src/CBot/CBotCall.cpp index 17871abf..8784fabd 100644 --- a/src/CBot/CBotCall.cpp +++ b/src/CBot/CBotCall.cpp @@ -245,7 +245,7 @@ fund: CBotStack* pile2 = pile->AddStack(); pile2->SetVar( pResult ); - pile->SetError(0, token); // for the position on error + away + pile->SetError(CBotNoErr, token); // for the position on error + away return pt->Run( pStack ); #endif @@ -292,14 +292,14 @@ bool CBotCall::Run(CBotStack* pStack) CBotVar* pResult = pile2->GetVar(); CBotVar* pRes = pResult; - int Exception = 0; + int Exception = 0; // TODO: change this to CBotError int res = m_rExec(pVar, pResult, Exception, pStack->GetPUser()); if (res == false) { if (Exception!=0) { - pStack->SetError(Exception); + pStack->SetError(static_cast(Exception)); } if ( pResult != pRes ) delete pResult; // different result if made return false; diff --git a/src/CBot/CBotCallMethode.cpp b/src/CBot/CBotCallMethode.cpp index 0bc8184d..39b6084a 100644 --- a/src/CBot/CBotCallMethode.cpp +++ b/src/CBot/CBotCallMethode.cpp @@ -126,7 +126,7 @@ int CBotCallMethode::DoCall(long& nIdent, // then calls the routine external to the module - int Exception = 0; + int Exception = 0; // TODO: Change this to CBotError int res = pt->m_rExec(pThis, pVar, pResult, Exception, pStack->GetPUser()); pStack->SetVar(pResult); @@ -135,7 +135,7 @@ int CBotCallMethode::DoCall(long& nIdent, if (Exception!=0) { // pStack->SetError(Exception, pVar->GetToken()); - pStack->SetError(Exception, pToken); + pStack->SetError(static_cast(Exception), pToken); } delete pVarToDelete; return false; @@ -157,7 +157,7 @@ int CBotCallMethode::DoCall(long& nIdent, CBotVar* pVar = MakeListVars(ppVars, true); CBotVar* pVarToDelete = pVar; - int Exception = 0; + int Exception = 0; // TODO: Change this to CBotError int res = pt->m_rExec(pThis, pVar, pResult, Exception, pStack->GetPUser()); pStack->SetVar(pResult); @@ -166,7 +166,7 @@ int CBotCallMethode::DoCall(long& nIdent, if (Exception!=0) { // pStack->SetError(Exception, pVar->GetToken()); - pStack->SetError(Exception, pToken); + pStack->SetError(static_cast(Exception), pToken); } delete pVarToDelete; return false; diff --git a/src/CBot/CBotInstr/CBotExprVar.cpp b/src/CBot/CBotInstr/CBotExprVar.cpp index 98f47cf5..57bee4e3 100644 --- a/src/CBot/CBotInstr/CBotExprVar.cpp +++ b/src/CBot/CBotInstr/CBotExprVar.cpp @@ -286,7 +286,7 @@ bool CBotExprVar::ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* prevToke pVar = pj->FindVar(m_nIdent, true); // tries with the variable update if necessary if (pVar == nullptr) { - pj->SetError(1, &m_token); + pj->SetError(static_cast(1), &m_token); // TODO: yeah, don't care that this exception doesn't exist ~krzys_h return false; } if ( m_next3 != nullptr && diff --git a/src/CBot/CBotInstr/CBotFunction.cpp b/src/CBot/CBotInstr/CBotFunction.cpp index 9a4129aa..92352455 100644 --- a/src/CBot/CBotInstr/CBotFunction.cpp +++ b/src/CBot/CBotInstr/CBotFunction.cpp @@ -380,7 +380,7 @@ bool CBotFunction::Execute(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance) if ( !m_Block->Execute(pile) ) { if ( pile->GetError() < 0 ) - pile->SetError( 0 ); + pile->SetError( CBotNoErr ); else return false; } diff --git a/src/CBot/CBotInstr/CBotLeftExpr.cpp b/src/CBot/CBotInstr/CBotLeftExpr.cpp index 4ac6a4e4..56f124f1 100644 --- a/src/CBot/CBotInstr/CBotLeftExpr.cpp +++ b/src/CBot/CBotInstr/CBotLeftExpr.cpp @@ -222,7 +222,7 @@ bool CBotLeftExpr::ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevT pVar = pile->FindVar(m_nIdent); if (pVar == nullptr) { - pile->SetError(2, &m_token); + pile->SetError(static_cast(2), &m_token); // TODO: yup, another unknown error ~krzys_h return false; } diff --git a/src/CBot/CBotInstr/CBotThrow.cpp b/src/CBot/CBotInstr/CBotThrow.cpp index 44c43f07..6393239f 100644 --- a/src/CBot/CBotInstr/CBotThrow.cpp +++ b/src/CBot/CBotInstr/CBotThrow.cpp @@ -83,7 +83,7 @@ bool CBotThrow::Execute(CBotStack* &pj) int val = pile->GetVal(); if ( val < 0 ) val = CBotErrBadThrow; - pile->SetError( val, &m_token ); + pile->SetError( static_cast(val), &m_token ); return pj->Return( pile ); } diff --git a/src/CBot/CBotInstr/CBotTry.cpp b/src/CBot/CBotInstr/CBotTry.cpp index 5cf57904..ac890596 100644 --- a/src/CBot/CBotInstr/CBotTry.cpp +++ b/src/CBot/CBotInstr/CBotTry.cpp @@ -109,7 +109,7 @@ bool CBotTry::Execute(CBotStack* &pj) pile1->IncState(); pile2->SetState(val); // stores the error number - pile1->SetError(0); // for now there is are more errors! + pile1->SetError(CBotNoErr); // for now there is are more errors! if ( val == 0 && CBotStack::m_initimer < 0 ) // mode step? return false; // does not make the catch @@ -158,7 +158,7 @@ bool CBotTry::Execute(CBotStack* &pj) if (!m_FinalInst->Execute(pile2) && pile2->IsOk()) return false; if (!pile2->IsOk()) return pj->Return(pile2); // keep this exception - pile2->SetError(pile1->GetState()==-1 ? val : 0); // gives the initial error + pile2->SetError(pile1->GetState()==-1 ? static_cast(val) : CBotNoErr); // gives the initial error return pj->Return(pile2); } @@ -167,7 +167,7 @@ bool CBotTry::Execute(CBotStack* &pj) if ( val != 0 && m_ListCatch == nullptr && m_FinalInst == nullptr ) return pj->Return(pile2); // ends the try without exception - pile1->SetError(val); // gives the error + pile1->SetError(static_cast(val)); // gives the error return false; // it's not for us } diff --git a/src/CBot/CBotInstr/CBotTwoOpExpr.cpp b/src/CBot/CBotInstr/CBotTwoOpExpr.cpp index bb3375fc..43d7c0dd 100644 --- a/src/CBot/CBotInstr/CBotTwoOpExpr.cpp +++ b/src/CBot/CBotInstr/CBotTwoOpExpr.cpp @@ -287,7 +287,7 @@ bool VarIsNAN(const CBotVar* var) return var->GetInit() > CBotVar::InitType::DEF; } -bool IsNan(CBotVar* left, CBotVar* right, int* err = nullptr) +bool IsNan(CBotVar* left, CBotVar* right, CBotError* err = nullptr) { if ( VarIsNAN(left) || VarIsNAN(right) ) { @@ -394,7 +394,7 @@ bool CBotTwoOpExpr::Execute(CBotStack* &pStack) if ( TypeRes == CBotTypClass ) temp = CBotVar::Create( static_cast(nullptr), CBotTypResult(CBotTypIntrinsic, type1.GetClass() ) ); else temp = CBotVar::Create( static_cast(nullptr), TypeRes ); - int err = 0; + CBotError err = CBotNoErr; // is a operation according to request CBotVar* left = pStk1->GetVar(); CBotVar* right = pStk2->GetVar(); diff --git a/src/CBot/CBotProgram.cpp b/src/CBot/CBotProgram.cpp index f65d8e29..c2cc8169 100644 --- a/src/CBot/CBotProgram.cpp +++ b/src/CBot/CBotProgram.cpp @@ -47,7 +47,7 @@ CBotProgram::CBotProgram() m_pStack = nullptr; m_pInstance = nullptr; - m_ErrorCode = 0; + m_ErrorCode = CBotNoErr; m_Ident = 0; } @@ -60,7 +60,7 @@ CBotProgram::CBotProgram(CBotVar* pInstance) m_pStack = nullptr; m_pInstance = pInstance; - m_ErrorCode = 0; + m_ErrorCode = CBotNoErr; m_Ident = 0; } @@ -82,7 +82,7 @@ CBotProgram::~CBotProgram() } //////////////////////////////////////////////////////////////////////////////// -bool CBotProgram::Compile(const std::string& program, std::vector& ListFonctions, void* pUser) +bool CBotProgram::Compile(const std::string& program, std::vector& functions, void* pUser) { int error = 0; Stop(); @@ -93,8 +93,8 @@ bool CBotProgram::Compile(const std::string& program, std::vector& m_pClass = nullptr; delete m_Prog; m_Prog= nullptr; - ListFonctions.clear(); - m_ErrorCode = 0; + functions.clear(); + m_ErrorCode = CBotNoErr; // transforms the program in Tokens CBotToken* pBaseToken = CBotToken::CompileTokens(program, error); @@ -154,7 +154,7 @@ bool CBotProgram::Compile(const std::string& program, std::vector& { m_bCompileClass = false; CBotFunction::Compile(p, pStack, next); - if (next->IsExtern()) ListFonctions.push_back(next->GetName()/* + next->GetParams()*/); + if (next->IsExtern()) functions.push_back(next->GetName()/* + next->GetParams()*/); next->m_pProg = this; // keeps pointers to the module next = next->Next(); } @@ -233,7 +233,7 @@ bool CBotProgram::Run(void* pUser, int timer) if (m_pStack == nullptr || m_pRun == nullptr) goto error; - m_ErrorCode = 0; + m_ErrorCode = CBotNoErr; m_pStack->Reset(pUser); // empty the possible previous error, and resets the timer if ( timer >= 0 ) m_pStack->SetTimer(timer); @@ -286,23 +286,23 @@ void CBotProgram::Stop() } //////////////////////////////////////////////////////////////////////////////// -bool CBotProgram::GetRunPos(std::string& FunctionName, int& start, int& end) +bool CBotProgram::GetRunPos(std::string& functionName, int& start, int& end) { - FunctionName = nullptr; + functionName = nullptr; start = end = 0; if (m_pStack == nullptr) return false; - m_pStack->GetRunPos(FunctionName, start, end); + m_pStack->GetRunPos(functionName, start, end); return true; } //////////////////////////////////////////////////////////////////////////////// -CBotVar* CBotProgram::GetStackVars(std::string& FunctionName, int level) +CBotVar* CBotProgram::GetStackVars(std::string& functionName, int level) { - FunctionName = nullptr; + functionName.clear(); if (m_pStack == nullptr) return nullptr; - return m_pStack->GetStackVars(FunctionName, level); + return m_pStack->GetStackVars(functionName, level); } //////////////////////////////////////////////////////////////////////////////// @@ -312,7 +312,7 @@ void CBotProgram::SetTimer(int n) } //////////////////////////////////////////////////////////////////////////////// -int CBotProgram::GetError() +CBotError CBotProgram::GetError() { return m_ErrorCode; } @@ -330,7 +330,7 @@ long CBotProgram::GetIdent() } //////////////////////////////////////////////////////////////////////////////// -bool CBotProgram::GetError(int& code, int& start, int& end) +bool CBotProgram::GetError(CBotError& code, int& start, int& end) { code = m_ErrorCode; start = m_ErrorStart; @@ -339,7 +339,7 @@ bool CBotProgram::GetError(int& code, int& start, int& end) } //////////////////////////////////////////////////////////////////////////////// -bool CBotProgram::GetError(int& code, int& start, int& end, CBotProgram* &pProg) +bool CBotProgram::GetError(CBotError& code, int& start, int& end, CBotProgram*& pProg) { code = m_ErrorCode; start = m_ErrorStart; @@ -348,20 +348,6 @@ bool CBotProgram::GetError(int& code, int& start, int& end, CBotProgram* &pProg) return code > 0; } -//////////////////////////////////////////////////////////////////////////////// -std::string CBotProgram::GetErrorText(int code) -{ - std::string TextError = LoadString(static_cast(code)); - - if (TextError.empty()) - { - char buf[100]; - sprintf(buf, "Exception numéro %d.", code); - TextError = buf; - } - return TextError; -} - //////////////////////////////////////////////////////////////////////////////// CBotFunction* CBotProgram::GetFunctions() { @@ -472,18 +458,18 @@ int CBotProgram::GetVersion() //////////////////////////////////////////////////////////////////////////////// void CBotProgram::Init() { - CBotToken::DefineNum("CBotErrZeroDiv", CBotErrZeroDiv); // division by zero - CBotToken::DefineNum("CBotErrNotInit", CBotErrNotInit); // uninitialized variable - CBotToken::DefineNum("CBotErrBadThrow", CBotErrBadThrow); // throw a negative value - CBotToken::DefineNum("CBotErrNoRetVal", CBotErrNoRetVal); // function did not return results - CBotToken::DefineNum("CBotErrNoRun", CBotErrNoRun); // active Run () without a function // TODO: Is this actually a runtime error? - CBotToken::DefineNum("CBotErrUndefFunc", CBotErrUndefFunc); // Calling a function that no longer exists - CBotToken::DefineNum("CBotErrNotClass", CBotErrNotClass); // Class no longer exists - CBotToken::DefineNum("CBotErrNull", CBotErrNull); // Attempted to use a null pointer - CBotToken::DefineNum("CBotErrNan", CBotErrNan); // Can't do operations on nan - CBotToken::DefineNum("CBotErrOutArray", CBotErrOutArray); // Attempted access out of bounds of an array - CBotToken::DefineNum("CBotErrStackOver", CBotErrStackOver); // Stack overflow - CBotToken::DefineNum("CBotErrDeletedPtr", CBotErrDeletedPtr); // Attempted to use deleted object + CBotToken::DefineNum("CBotErrZeroDiv", CBotErrZeroDiv); // division by zero + CBotToken::DefineNum("CBotErrNotInit", CBotErrNotInit); // uninitialized variable + CBotToken::DefineNum("CBotErrBadThrow", CBotErrBadThrow); // throw a negative value + CBotToken::DefineNum("CBotErrNoRetVal", CBotErrNoRetVal); // function did not return results + CBotToken::DefineNum("CBotErrNoRun", CBotErrNoRun); // active Run () without a function // TODO: Is this actually a runtime error? + CBotToken::DefineNum("CBotErrUndefFunc", CBotErrUndefFunc); // Calling a function that no longer exists + CBotToken::DefineNum("CBotErrNotClass", CBotErrNotClass); // Class no longer exists + CBotToken::DefineNum("CBotErrNull", CBotErrNull); // Attempted to use a null pointer + CBotToken::DefineNum("CBotErrNan", CBotErrNan); // Can't do operations on nan + CBotToken::DefineNum("CBotErrOutArray", CBotErrOutArray); // Attempted access out of bounds of an array + CBotToken::DefineNum("CBotErrStackOver", CBotErrStackOver); // Stack overflow + CBotToken::DefineNum("CBotErrDeletedPtr", CBotErrDeletedPtr); // Attempted to use deleted object CBotProgram::AddFunction("sizeof", rSizeOf, cSizeOf ); diff --git a/src/CBot/CBotProgram.h b/src/CBot/CBotProgram.h index 50c62f63..4ded0aac 100644 --- a/src/CBot/CBotProgram.h +++ b/src/CBot/CBotProgram.h @@ -19,205 +19,286 @@ #pragma once -// Modules inlcude #include "CBot/CBotTypResult.h" - #include "CBot/CBotEnums.h" -// Local include - -// Global include #include -// Forward declaration class CBotFunction; class CBotClass; class CBotStack; class CBotVar; -/*! - * \brief The CBotProgram class Main class managing CBot program. +/** + * \brief Class that manages a CBot program. This is the main entry point into the CBot engine. + * + * \section Init Engine initialization / destruction + * To initialize the CBot engine, call CBotProgram::Init(). This function should be only called once. + * + * Afterwards, you can start defining custom functions, constants and classes. See: + * * CBotProgram::AddFunction() + * * CBotProgram::DefineNum() + * * CBotClass::Create() + * + * Next, compile and run programs. + * * Compile() + * * Start() + * * Run() + * * Stop() + * + * After you are finished, free the memory used by the CBot engine by calling CBotProgram::Free(). + * + * \section Example Example usage + * \code + * // Initialize the engine + * CBotProgram::Init(); + * + * // Add some standard functions + * CBotProgram::AddFunction("message", rMessage, cMessage); + * + * // Compile the program + * std::vector externFunctions; + * CBotProgram* program = new CBotProgram(); + * bool ok = program->Compile(code.c_str(), externFunctions, nullptr); + * if (!ok) + * { + * CBotError error; + * int cursor1, cursor2; + * program->GetError(error, cursor1, cursor2); + * // Handle the error + * } + * + * // Run the program + * program->Start(externFunctions[0]); + * while (!program->Run()); + * + * // Cleanup + * CBotProgram::Free(); + * \endcode */ class CBotProgram { public: - - /*! - * \brief CBotProgram + /** + * \brief Constructor */ CBotProgram(); - /*! - * \brief CBotProgram - * \param pInstance + /** + * \brief Constructor + * \param pInstance Variable to pass to the program as "this" */ CBotProgram(CBotVar* pInstance); - /*! - * \brief ~CBotProgram + /** + * \brief Destructor */ ~CBotProgram(); - /*! - * \brief Init Initializes the module (defined keywords for errors) should - * be done once (and only one) at the beginning. + /** + * \brief Initializes the module, should be done once (and only once) at the beginning */ static void Init(); - /*! - * \brief Free Frees the static memory areas. + /** + * \brief Frees the static memory areas */ static void Free(); - /*! - * \brief GetVersion Gives the version of the library CBOT. - * \return + /** + * \brief Returns version of the CBot library + * \return A number representing the current library version */ static int GetVersion(); - /*! - * \brief Compile compiles the program given in text. - * \param program - * \param ListFonctions Returns the names of functions declared as extern. - * \param pUser Can pass a pointer to routines defined by AddFunction. - * \return false if an error at compile. - * \see GetCompileError() to retrieve the error. + /** + * \brief Compile compiles the program given as string + * \param program Code to compile + * \param[out] functions Returns the names of functions declared as extern + * \param pUser Optional pointer to be passed to compile function (see AddFunction()) + * \return true if compilation is successful, false if an compilation error occurs + * \see GetError() to retrieve the error */ - bool Compile(const std::string& program, std::vector& ListFonctions, void* pUser = nullptr); + bool Compile(const std::string& program, std::vector& functions, void* pUser = nullptr); - /*! - * \brief SetIdent Associates an identifier with the instance CBotProgram. - * \param n + /** + * \brief Associates an identifier with this instance of CBotProgram */ void SetIdent(long n); - /*! - * \brief GetIdent Gives the identifier. - * \return + /** + * \brief Returns the identifier + * \see SetIdent */ long GetIdent(); - /*! - * \brief GetError - * \return + /** + * \brief Returns the last error + * \return Error code + * \see GetError(CBotError&, int&, int&) for error location in the code */ - int GetError(); + CBotError GetError(); - /*! - * \brief GetError - * \param code - * \param start - * \param end - * \return + /** + * \brief Returns the last error + * \param[out] code Error code + * \param[out] start Starting position in the code string of this error + * \param[out] end Ending position in the code string of this error + * \return false if no error has occured */ - bool GetError(int& code, int& start, int& end); + bool GetError(CBotError& code, int& start, int& end); - /*! - * \brief GetError - * \param code - * \param start Delimits the start block where the error occured. - * \param end Delimits the end block where the error occured. - * \param pProg Lets you know what "module" has produced runtime error. - * \return If true gives the error found in the compilation or execution. + /** + * \brief Returns the last error + * \param[out] code Error code + * \param[out] start Starting position in the code string of this error + * \param[out] end Ending position in the code string of this error + * \param[out] pProg Program that caused the error (TODO: This always returns "this"... what?) + * \return false if no error has occured */ - bool GetError(int& code, int& start, int& end, CBotProgram* &pProg); + bool GetError(CBotError& code, int& start, int& end, CBotProgram*& pProg); - /*! - * \brief GetErrorText - * \param code - * \return - */ - static std::string GetErrorText(int code); - - /*! - * \brief Start Defines what function should be executed. The program does - * nothing, we must call Run () for this. - * \param name - * \return false if the funtion name is not found + /** + * \brief Starts the program using given function as an entry point. The function must be declared as "extern" + * \param name Name of function to start + * \return true if the program was started, false if the function name is not found + * \see Compile() returns list of extern functions found in the code */ bool Start(const std::string& name); - /*! - * \brief Run Executes the program. - * \param pUser - * \param timer timer = 0 allows to advance step by step. - * \return false if the program was suspended, true if the program ended - * with or without error. + /** + * \brief Executes the program + * \param pUser Custom pointer to be passed to execute function (see AddFunction()) + * \param timer + * \parblock + * * timer < 0 do nothing + * * timer >= 0 call SetTimer(int timer) before executing + * \parblockend + * \return true if the program execution finished, false if the program is suspended (you then have to call Run() again) */ bool Run(void* pUser = nullptr, int timer = -1); - /*! - * \brief GetRunPos Gives the position in the executing program - * \param FunctionName is a pointer made to the name of the function - * \param start start and end position in the text of the token processing - * \param end + /** + * \brief GetRunPos Gives the current position in the executing program + * \param[out] functionName Name of the currently executed function + * \param[out] start Starting position in the code string of currently executed instruction + * \param[out] end Ending position in the code string of currently executed instruction * \return false if it is not running (program completion) */ - bool GetRunPos(std::string& FunctionName, int& start, int& end); + bool GetRunPos(std::string& functionName, int& start, int& end); - /*! - * \brief GetStackVars provides the pointer to the variables on the - * execution stack level is an input parameter, 0 for the last level, -1, - * -2, etc. for the other levels the return value (CBotVar *) is a variable. - * that can be processed as the list of parameters received by a routine - * list (or nullptr) - * \param FunctionName gives the name of the function where are these - * variables. FunctionName == nullptr means that is more in a program - * (depending on level) - * \param level - * \return + /** + * \brief Provides the pointer to the variables on the execution stack + * \param[out] functionName Name of the function that this stack is part of + * \param level 0 for the last level, -1, -2 etc. for previous ones + * \return Variables on the given stack level. Process using CBotVar::GetNext(). If the stack level is invalid, returns nullptr. */ - CBotVar* GetStackVars(std::string& FunctionName, int level); + CBotVar* GetStackVars(std::string& functionName, int level); - /*! - * \brief Stop stops execution of the program therefore quits "suspend" mode + /** + * \brief Stops execution of the program */ void Stop(); - /*! - * \brief SetTimer defines the number of steps (parts of instructions) to - * done in Run() before rendering hand "false" - * \TODO avant de rendre la main "false" - * \param n + /** + * \brief Sets the number of steps (parts of instructions) to execute in Run() before suspending the program execution + * \param n new timer value + * + * FIXME: Seems to be currently kind of broken (see issue #410) */ static void SetTimer(int n); - // - // - /*! - * \brief AddFunction Call this to add externally a new function used - * by the program CBoT. See (**) at end of this file for more details. - * \param name - * \param rExec - * \param rCompile - * \return + /** + * \brief Add a function that can be called from CBot + * + * To define an external function, proceed as follows: + * + * 1. Define a function for compilation + * + * This function should take a list of function arguments (types only, no values!) and a user-defined void* pointer (can be passed in Compile()) as parameters, and return CBotTypResult. + * + * Usually, name of this function is prefixed with "c". + * + * The function should iterate through the provided parameter list and verify that they match.
+ * If they don't, then return CBotTypResult with an appropariate error code (see ::CBotError).
+ * If they do, return CBotTypResult with the function's return type + * + * \code + * CBotTypResult cMessage(CBotVar* &var, void* user) + * { + * if (var == nullptr) return CBotTypResult(CBotErrLowParam); // Not enough parameters + * if (var->GetType() != CBotTypString) return CBotTypResult(CBotErrBadString); // String expected + * + * var = var->GetNext(); // Get the next parameter + * if (var != nullptr) return CBotTypResult(CBotErrOverParam); // Too many parameters + * + * return CBotTypResult(CBotTypFloat); // This function returns float (it may depend on parameters given!) + * } + * \endcode + * + * 2. Define a function for execution + * + * This function should take: + * * a list of parameters + * * pointer to a result variable (a variable of type given at compilation time will be provided) + * * pointer to an exception variable + * * user-defined pointer (can be passed in Run()) + * + * This function returns true if execution of this function is finished, or false to suspend the program and call this function again on next Run() cycle. + * + * Usually, execution functions are prefixed with "r". + * + * \code + * bool rMessage(CBotVar* var, CBotVar* result, int& exception, void* user) + * { + * std::string message = var->GetValString(); + * std::cout << message << std::endl; + * return true; // Execution finished + * } + * \endcode + * + * 3. Call AddFunction() to register the function in the CBot engine + * + * \code + * AddFunction("message", rMessage, cMessage); + * \endcode + * + * + * \param name Name of the function + * \param rExec Execution function + * \param rCompile Compilation function + * \return true */ static bool AddFunction(const std::string& name, bool rExec(CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser), CBotTypResult rCompile(CBotVar*& pVar, void* pUser)); - /*! - * \brief DefineNum - * \param name - * \param val - * \return + /** + * \brief Define a new constant + * \param name Name of the constant + * \param val Value of the constant + * \return true on success, false if unable to define (e.g. already defined) */ static bool DefineNum(const std::string& name, long val); /*! - * \brief SaveState Backup the execution status in the file the file must - * have been opened with the fopen call this dll (\TODO this library??) - * if the system crashes - * \param pf - * \return + * \brief Save the current execution status into a file + * \param pf file handle + * \paramblock + * This file handle must have been opened by this library! Otherwise crashes on Windows + * TODO: Verify this + * \endparamblock + * \return true on success, false on write error */ bool SaveState(FILE* pf); /*! - * \brief RestoreState Restores the state of execution from file the - * compiled program must obviously be the same. - * \param pf - * \return + * \brief Restore the execution state from a file + * + * The previous program code must be already recompiled to call this function + * + * \param pf file handle + * \return true on success, false on read error */ bool RestoreState(FILE* pf); @@ -225,6 +306,9 @@ public: * \brief GetPosition Gives the position of a routine in the original text * the user can select the item to find from the beginning to the end * see the above modes in CBotGet. + * + * TODO: Document this + * * \param name * \param start * \param stop @@ -239,76 +323,37 @@ public: CBotGet modestop = GetPosBloc); /*! - * \brief GetFunctions - * \return + * \brief Returns the list of all user-defined functions in this program as instances of CBotFunction + * + * This list includes all the functions (not only extern) + * + * \return Linked list of CBotFunction instances */ CBotFunction* GetFunctions(); /*! * \brief m_bCompileClass + * + * TODO: document this */ bool m_bCompileClass; private: - - //! The user-defined functions. + //! All user-defined functions CBotFunction* m_Prog; - //! The basic function for the execution. + //! The entry point function CBotFunction* m_pRun; - //! Classes defined in this part. + //! Classes defined in this program CBotClass* m_pClass; - //! Execution stack. + //! Execution stack CBotStack* m_pStack; - //! Instance of the parent class. + //! "this" variable CBotVar* m_pInstance; friend class CBotFunction; - int m_ErrorCode; + CBotError m_ErrorCode; int m_ErrorStart; int m_ErrorEnd; - //! Associated identifier. + //! Associated identifier long m_Ident; }; - -/* -(**) Note: - - To define an external function, proceed as follows: - - a) define a routine for compilation this routine receive list of parameters - (no values) and either returns a result type (CBotTyp... or 0 = void) - or an error number. - - b) define a routine for the execution this routine receive list of - parameters (with valeurs), a variable to store the result - (according to the given type at compile time) - - For example, a routine which calculates the mean of a parameter list - -int cMean(CBotVar* &pVar, std::string& ClassName) -{ - if ( pVar == nullptr ) return 6001; // there is no parameter! - while ( pVar != nullptr ) - { - if ( pVar->GetType() > CBotTypDouble ) return 6002; // this is not a number - pVar = pVar -> GetNext(); - } - return CBotTypFloat; // the type of the result may depend on the parameters! -} - - -bool rMean(CBotVar* pVar, CBotVar* pResult, int& Exception) -{ - float total = 0; - int nb = 0; - while (pVar != nullptr) - { - total += pVar->GetValFloat(); - pVar = pVar->GetNext(); - nb++; - } - pResult->SetValFloat(total/nb); // returns the mean value - return true; // operation fully completed -} - -*/ diff --git a/src/CBot/CBotStack.cpp b/src/CBot/CBotStack.cpp index 545c49f9..4b13df58 100644 --- a/src/CBot/CBotStack.cpp +++ b/src/CBot/CBotStack.cpp @@ -42,7 +42,7 @@ int CBotStack::m_initimer = ITIMER; int CBotStack::m_timer = 0; CBotVar* CBotStack::m_retvar = nullptr; -int CBotStack::m_error = 0; +CBotError CBotStack::m_error = CBotNoErr; int CBotStack::m_start = 0; int CBotStack::m_end = 0; std::string CBotStack::m_labelBreak=""; @@ -76,7 +76,7 @@ CBotStack* CBotStack::FirstStack() pp ++; } - m_error = 0; // avoids deadlocks because m_error is static + m_error = CBotNoErr; // avoids deadlocks because m_error is static return p; } @@ -358,7 +358,7 @@ bool CBotStack::StackOver() void CBotStack::Reset(void* pUser) { m_timer = m_initimer; // resets the timer - m_error = 0; + m_error = CBotNoErr; // m_start = 0; // m_end = 0; m_labelBreak.clear(); @@ -402,7 +402,7 @@ bool CBotStack::BreakReturn(CBotStack* pfils, const std::string& name) if (!m_labelBreak.empty() && (name.empty() || m_labelBreak != name)) return false; // it's not for me - m_error = 0; + m_error = CBotNoErr; m_labelBreak.clear(); return Return(pfils); } @@ -416,7 +416,7 @@ bool CBotStack::IfContinue(int state, const std::string& name) return false; // it's not for me m_state = state; // where again? - m_error = 0; + m_error = CBotNoErr; m_labelBreak.clear(); if ( m_next != EOX ) m_next->Delete(); // purge above stack return true; @@ -425,7 +425,7 @@ bool CBotStack::IfContinue(int state, const std::string& name) //////////////////////////////////////////////////////////////////////////////// void CBotStack::SetBreak(int val, const std::string& name) { - m_error = -val; // reacts as an Exception + m_error = static_cast(-val); // reacts as an Exception m_labelBreak = name; if (val == 3) // for a return { @@ -443,14 +443,14 @@ bool CBotStack::GetRetVar(bool bRet) if ( m_var ) delete m_var; m_var = m_retvar; m_retvar = nullptr; - m_error = 0; + m_error = CBotNoErr; return true; } return bRet; // interrupted by something other than return } //////////////////////////////////////////////////////////////////////////////// -int CBotStack::GetError(int& start, int& end) +CBotError CBotStack::GetError(int& start, int& end) { start = m_start; end = m_end; @@ -584,7 +584,7 @@ bool CBotStack::IncState(int limite) } //////////////////////////////////////////////////////////////////////////////// -void CBotStack::SetError(int n, CBotToken* token) +void CBotStack::SetError(CBotError n, CBotToken* token) { if ( n!= 0 && m_error != 0) return; // does not change existing error m_error = n; @@ -596,7 +596,7 @@ void CBotStack::SetError(int n, CBotToken* token) } //////////////////////////////////////////////////////////////////////////////// -void CBotStack::ResetError(int n, int start, int end) +void CBotStack::ResetError(CBotError n, int start, int end) { m_error = n; m_start = start; diff --git a/src/CBot/CBotStack.h b/src/CBot/CBotStack.h index 5e40fc3e..ba823383 100644 --- a/src/CBot/CBotStack.h +++ b/src/CBot/CBotStack.h @@ -22,6 +22,7 @@ // Modules inlcude #include "CBot/CBotDefines.h" #include "CBot/CBotTypResult.h" +#include "CBotEnums.h" // Local include @@ -81,7 +82,7 @@ public: * \param [out] end end of stack * \return error number */ - int GetError(int& start, int& end); + CBotError GetError(int& start, int& end); /** * \brief GetError Get error number @@ -201,9 +202,9 @@ public: bool GetRetVar(bool bRet); long GetVal(); - void SetError(int n, CBotToken* token = nullptr); + void SetError(CBotError n, CBotToken* token = nullptr); void SetPosError(CBotToken* token); - void ResetError(int n, int start, int end); + void ResetError(CBotError n, int start, int end); void SetBreak(int val, const std::string& name); void SetBotCall(CBotProgram* p); @@ -232,7 +233,7 @@ private: int m_state; int m_step; - static int m_error; + static CBotError m_error; static int m_start; static int m_end; static diff --git a/src/CBot/CBotTypResult.h b/src/CBot/CBotTypResult.h index 3cfa6fc0..085422f7 100644 --- a/src/CBot/CBotTypResult.h +++ b/src/CBot/CBotTypResult.h @@ -50,6 +50,12 @@ public: /** * \brief Constructor for pointer types and intrinsic classes + * + * This is equivalent to calling: + * \code + * CBotTypResult(type, CBotClass::Find(name)) + * \endcode + * * \param type type of created result, see ::CBotType * \param name name of the class */ diff --git a/src/CBot/CBotVar/CBotVar.cpp b/src/CBot/CBotVar/CBotVar.cpp index 80d04db8..aeab11db 100644 --- a/src/CBot/CBotVar/CBotVar.cpp +++ b/src/CBot/CBotVar/CBotVar.cpp @@ -586,17 +586,17 @@ void CBotVar::Power(CBotVar* left, CBotVar* right) } //////////////////////////////////////////////////////////////////////////////// -int CBotVar::Div(CBotVar* left, CBotVar* right) +CBotError CBotVar::Div(CBotVar* left, CBotVar* right) { assert(0); - return 0; + return CBotNoErr; } //////////////////////////////////////////////////////////////////////////////// -int CBotVar::Modulo(CBotVar* left, CBotVar* right) +CBotError CBotVar::Modulo(CBotVar* left, CBotVar* right) { assert(0); - return 0; + return CBotNoErr; } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/CBot/CBotVar/CBotVar.h b/src/CBot/CBotVar/CBotVar.h index d3202f46..8acd9cf5 100644 --- a/src/CBot/CBotVar/CBotVar.h +++ b/src/CBot/CBotVar/CBotVar.h @@ -27,6 +27,7 @@ // Global include #include +#include // Forward declaration class CBotVarClass; @@ -398,7 +399,7 @@ public: * \param right * \return */ - virtual int Div(CBotVar* left, CBotVar* right); + virtual CBotError Div(CBotVar* left, CBotVar* right); /*! * \brief Modulo Remainder of division @@ -406,7 +407,7 @@ public: * \param right * \return */ - virtual int Modulo(CBotVar* left, CBotVar* right); + virtual CBotError Modulo(CBotVar* left, CBotVar* right); /*! * \brief Power diff --git a/src/CBot/CBotVar/CBotVarClass.cpp b/src/CBot/CBotVar/CBotVarClass.cpp index 484cbb25..0dcef3ea 100644 --- a/src/CBot/CBotVar/CBotVarClass.cpp +++ b/src/CBot/CBotVar/CBotVarClass.cpp @@ -411,7 +411,8 @@ void CBotVarClass::DecrementUse() // m_error is static in the stack // saves the value for return - int err, start, end; + CBotError err; + int start, end; CBotStack* pile = nullptr; err = pile->GetError(start,end); // stack == nullptr it does not bother! diff --git a/src/CBot/CBotVar/CBotVarFloat.cpp b/src/CBot/CBotVar/CBotVarFloat.cpp index 23a1977f..886d9730 100644 --- a/src/CBot/CBotVar/CBotVarFloat.cpp +++ b/src/CBot/CBotVar/CBotVarFloat.cpp @@ -128,7 +128,7 @@ void CBotVarFloat::Power(CBotVar* left, CBotVar* right) } //////////////////////////////////////////////////////////////////////////////// -int CBotVarFloat::Div(CBotVar* left, CBotVar* right) +CBotError CBotVarFloat::Div(CBotVar* left, CBotVar* right) { float r = right->GetValFloat(); if ( r != 0 ) @@ -136,11 +136,11 @@ int CBotVarFloat::Div(CBotVar* left, CBotVar* right) m_val = left->GetValFloat() / r; m_binit = CBotVar::InitType::DEF; } - return ( r == 0 ? CBotErrZeroDiv : 0 ); + return ( r == 0 ? CBotErrZeroDiv : CBotNoErr ); } //////////////////////////////////////////////////////////////////////////////// -int CBotVarFloat::Modulo(CBotVar* left, CBotVar* right) +CBotError CBotVarFloat::Modulo(CBotVar* left, CBotVar* right) { float r = right->GetValFloat(); if ( r != 0 ) @@ -148,7 +148,7 @@ int CBotVarFloat::Modulo(CBotVar* left, CBotVar* right) m_val = static_cast(fmod( left->GetValFloat() , r )); m_binit = CBotVar::InitType::DEF; } - return ( r == 0 ? CBotErrZeroDiv : 0 ); + return ( r == 0 ? CBotErrZeroDiv : CBotNoErr ); } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/CBot/CBotVar/CBotVarFloat.h b/src/CBot/CBotVar/CBotVarFloat.h index c8821a56..7cff1e78 100644 --- a/src/CBot/CBotVar/CBotVarFloat.h +++ b/src/CBot/CBotVar/CBotVarFloat.h @@ -20,6 +20,7 @@ #pragma once // Modules inlcude +#include #include "CBot/CBotVar/CBotVar.h" // Local include @@ -105,7 +106,7 @@ public: * \param right * \return */ - int Div(CBotVar* left, CBotVar* right) override; + CBotError Div(CBotVar* left, CBotVar* right) override; /*! * \brief Modulo Remainder of division. @@ -113,7 +114,7 @@ public: * \param right * \return */ - int Modulo(CBotVar* left, CBotVar* right) override; + CBotError Modulo(CBotVar* left, CBotVar* right) override; /*! * \brief Power diff --git a/src/CBot/CBotVar/CBotVarInt.cpp b/src/CBot/CBotVar/CBotVarInt.cpp index e6ed9d47..614a959f 100644 --- a/src/CBot/CBotVar/CBotVarInt.cpp +++ b/src/CBot/CBotVar/CBotVarInt.cpp @@ -131,7 +131,7 @@ void CBotVarInt::Power(CBotVar* left, CBotVar* right) } //////////////////////////////////////////////////////////////////////////////// -int CBotVarInt::Div(CBotVar* left, CBotVar* right) +CBotError CBotVarInt::Div(CBotVar* left, CBotVar* right) { int r = right->GetValInt(); if ( r != 0 ) @@ -139,11 +139,11 @@ int CBotVarInt::Div(CBotVar* left, CBotVar* right) m_val = left->GetValInt() / r; m_binit = CBotVar::InitType::DEF; } - return ( r == 0 ? CBotErrZeroDiv : 0 ); + return ( r == 0 ? CBotErrZeroDiv : CBotNoErr ); } //////////////////////////////////////////////////////////////////////////////// -int CBotVarInt::Modulo(CBotVar* left, CBotVar* right) +CBotError CBotVarInt::Modulo(CBotVar* left, CBotVar* right) { int r = right->GetValInt(); if ( r != 0 ) @@ -151,7 +151,7 @@ int CBotVarInt::Modulo(CBotVar* left, CBotVar* right) m_val = left->GetValInt() % r; m_binit = CBotVar::InitType::DEF; } - return ( r == 0 ? CBotErrZeroDiv : 0 ); + return ( r == 0 ? CBotErrZeroDiv : CBotNoErr ); } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/CBot/CBotVar/CBotVarInt.h b/src/CBot/CBotVar/CBotVarInt.h index 16da7882..9cce4e9b 100644 --- a/src/CBot/CBotVar/CBotVarInt.h +++ b/src/CBot/CBotVar/CBotVarInt.h @@ -20,6 +20,7 @@ #pragma once // Modules inlcude +#include #include "CBot/CBotVar/CBotVar.h" // Local include @@ -105,7 +106,7 @@ public: * \param right * \return */ - int Div(CBotVar* left, CBotVar* right) override; + CBotError Div(CBotVar* left, CBotVar* right) override; /*! * \brief Modulo @@ -113,7 +114,7 @@ public: * \param right * \return */ - int Modulo(CBotVar* left, CBotVar* right) override; + CBotError Modulo(CBotVar* left, CBotVar* right) override; /*! * \brief Power diff --git a/src/CBot/README.txt b/src/CBot/README.txt new file mode 100644 index 00000000..f6dcb5fb --- /dev/null +++ b/src/CBot/README.txt @@ -0,0 +1,4 @@ +/** + * \dir src/CBot + * \brief CBot library + */ \ No newline at end of file diff --git a/src/script/script.cpp b/src/script/script.cpp index 4e70817c..0a8b79ef 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -165,7 +165,7 @@ bool CScript::CheckToken() if ( !m_object->GetCheckToken() ) return true; - m_error = 0; + m_error = CBotNoErr; m_title[0] = 0; m_mainFunction[0] = 0; m_token[0] = 0; @@ -194,7 +194,7 @@ bool CScript::CheckToken() if ( !m_main->IsProhibitedToken(token.c_str()) ) { - m_error = ERR_PROHIBITEDTOKEN; + m_error = static_cast(ERR_PROHIBITEDTOKEN); m_cursor1 = cursor1; m_cursor2 = cursor2; strcpy(m_title, ""); @@ -212,7 +212,7 @@ bool CScript::CheckToken() if ( used[i] == 0 ) // token not used? { strcpy(m_token, m_main->GetObligatoryToken(i)); - m_error = ERR_OBLIGATORYTOKEN; + m_error = static_cast(ERR_OBLIGATORYTOKEN); strcpy(m_title, ""); m_mainFunction[0] = 0; CBotToken::Delete(allBt); @@ -232,7 +232,7 @@ bool CScript::Compile() int i; std::string p; - m_error = 0; + m_error = CBotNoErr; m_cursor1 = 0; m_cursor2 = 0; m_title[0] = 0; @@ -815,7 +815,7 @@ void CScript::GetError(std::string& error) } else { - if ( m_error == ERR_OBLIGATORYTOKEN ) + if ( m_error == static_cast(ERR_OBLIGATORYTOKEN) ) { std::string s; GetResource(RES_ERR, m_error, s); diff --git a/src/script/script.h b/src/script/script.h index 7bf9b62f..395c4a4b 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -123,7 +123,7 @@ protected: char m_mainFunction[50] = {}; char m_filename[50] = {}; // file name char m_token[50] = {}; // missing instruction - int m_error = 0; // error (0=ok) + CBotError m_error = CBotNoErr; // error (0=ok) int m_cursor1 = 0; int m_cursor2 = 0; boost::optional m_returnValue = boost::none; diff --git a/test/cbot/console/main.cpp b/test/cbot/console/main.cpp index fc0e5cc5..b5e24b41 100644 --- a/test/cbot/console/main.cpp +++ b/test/cbot/console/main.cpp @@ -47,7 +47,8 @@ int main(int argc, char* argv[]) std::unique_ptr program{new CBotProgram(nullptr)}; if (!program->Compile(code.c_str(), externFunctions, nullptr)) { - int error, cursor1, cursor2; + CBotError error; + int cursor1, cursor2; program->GetError(error, cursor1, cursor2); std::string errorStr; GetResource(RES_CBOT, error, errorStr); @@ -74,7 +75,8 @@ int main(int argc, char* argv[]) while (!program->Run(nullptr)); // Run the program - int error, cursor1, cursor2; + CBotError error; + int cursor1, cursor2; program->GetError(error, cursor1, cursor2); if (error != 0) {