Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Mar 31, 2010, 12:04:30 AM (15 years ago)
Author:
rgrieder
Message:

Improved Lua error handling: Clearer messages and debugger hook.
So, if the IOConsole is not running and a runtime error occurs, the lua debugger automatically gets started.

Location:
code/branches/gamestate/src/libraries/core
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • code/branches/gamestate/src/libraries/core/LuaState.cc

    r6655 r6660  
    3737
    3838#include "util/Debug.h"
     39#include "util/Exception.h"
     40#include "util/ScopeGuard.h"
     41#include "IOConsole.h"
    3942#include "Resource.h"
    4043#include "ToluaBindCore.h"
     
    5457        // Create new lua state and configure it
    5558        luaState_ = lua_open();
     59        Loki::ScopeGuard luaStateGuard = Loki::MakeGuard(&lua_close, luaState_);
    5660#if LUA_VERSION_NUM == 501
    5761        luaL_openlibs(luaState_);
     
    7882
    7983        // Parse init script
    80         this->doFile("LuaStateInit.lua");
     84        if (!this->doFile("LuaStateInit.lua"))
     85            ThrowException(InitialisationFailed, "Running LuaStateInit.lua failed");
     86
     87        luaStateGuard.Dismiss();
    8188    }
    8289
     
    96103    }
    97104
    98     void LuaState::includeFile(const std::string& filename)
     105    bool LuaState::includeFile(const std::string& filename)
    99106    {
    100107        shared_ptr<ResourceInfo> sourceInfo = this->getFileInfo(filename);
    101108        if (sourceInfo != NULL)
    102             this->includeString(Resource::open(sourceInfo)->getAsString(), sourceInfo);
    103         else
    104             COUT(2) << "LuaState: Cannot include file '" << filename << "'." << std::endl;
    105     }
    106 
    107     void LuaState::includeString(const std::string& code, const shared_ptr<ResourceInfo>& sourceFileInfo)
     109            return this->includeString(Resource::open(sourceInfo)->getAsString(), sourceInfo);
     110        else
     111        {
     112            COUT(2) << "LuaState: Cannot include file '" << filename << "' (not found)." << std::endl;
     113            return false;
     114        }
     115    }
     116
     117    bool LuaState::includeString(const std::string& code, const shared_ptr<ResourceInfo>& sourceFileInfo)
    108118    {
    109119        // Parse string with provided include parser (otherwise don't preparse at all)
     
    121131        }
    122132
    123         this->doString(luaInput, sourceFileInfo);
     133        bool returnValue = this->doString(luaInput, sourceFileInfo);
    124134
    125135        if (sourceFileInfo != NULL)
     
    129139                this->sourceCodeMap_.erase(sourceFileInfo->filename);
    130140        }
    131     }
    132 
    133     void LuaState::doFile(const std::string& filename)
     141
     142        return returnValue;
     143    }
     144
     145    bool LuaState::doFile(const std::string& filename)
    134146    {
    135147        shared_ptr<ResourceInfo> sourceInfo = this->getFileInfo(filename);
    136148        if (sourceInfo != NULL)
    137             this->doString(Resource::open(sourceInfo)->getAsString(), sourceInfo);
    138         else
    139             COUT(2) << "LuaState: Cannot do file '" << filename << "'." << std::endl;
    140     }
    141 
    142     void LuaState::doString(const std::string& code, const shared_ptr<ResourceInfo>& sourceFileInfo)
     149            return this->doString(Resource::open(sourceInfo)->getAsString(), sourceInfo);
     150        else
     151        {
     152            COUT(2) << "LuaState: Cannot do file '" << filename << "' (not found)." << std::endl;
     153            return false;
     154        }
     155    }
     156
     157    bool LuaState::doString(const std::string& code, const shared_ptr<ResourceInfo>& sourceFileInfo)
    143158    {
    144159        // Save the old source file info
     
    161176        }
    162177
    163         int error = 0;
     178        // Push custom error handler that uses the debugger
     179        int errorHandler = 1;
     180        lua_getglobal(this->luaState_, "errorHandler");
     181        if (lua_isnil(this->luaState_, -1))
     182        {
     183            lua_pop(this->luaState_, 1);
     184            errorHandler = 0;
     185        }
     186
    164187#if LUA_VERSION_NUM != 501
    165188        LoadS ls;
    166189        ls.s = code.c_str();
    167190        ls.size = code.size();
    168         error = lua_load(luaState_, &orxonox::LuaState::lua_Chunkreader, &ls, chunkname.c_str());
     191        int error = lua_load(luaState_, &orxonox::LuaState::lua_Chunkreader, &ls, chunkname.c_str());
    169192#else
    170         error = luaL_loadbuffer(luaState_, code.c_str(), code.size(), chunkname.c_str());
     193        int error = luaL_loadbuffer(luaState_, code.c_str(), code.size(), chunkname.c_str());
    171194#endif
    172195
    173         // execute the chunk
     196        switch (error)
     197        {
     198        case LUA_ERRSYNTAX: // Syntax error
     199            COUT(1) << "Lua syntax error: " << lua_tostring(luaState_, -1) << std::endl;
     200            break;
     201        case LUA_ERRMEM:    // Memory allocation error
     202            COUT(1) << "Lua memory allocation error: Consult your dentist immediately!" << std::endl;
     203            lua_pop(luaState_, 1);
     204            break;
     205        }
     206
    174207        if (error == 0)
    175             error = lua_pcall(luaState_, 0, 1, 0);
     208        {
     209            // Execute the chunk in protected mode with an error handler function (stack index)
     210            error = lua_pcall(luaState_, 0, 1, errorHandler);
     211
     212            switch (error)
     213            {
     214            case LUA_ERRRUN: // Runtime error
     215                // Remove error string from stack (we already display the error in the
     216                // 'errorHandler' Lua function in LuaStateInit.lua)
     217                lua_pop(luaState_, 1);
     218                break;
     219            case LUA_ERRERR: // Error in the error handler
     220                COUT(1) << "Lua error in error handler: " << lua_tostring(luaState_, -1) << std::endl;
     221                break;
     222            case LUA_ERRMEM: // Memory allocation error
     223                COUT(1) << "Lua memory allocation error: Consult your dentist immediately!" << std::endl;
     224                lua_pop(luaState_, 1);
     225                break;
     226            }
     227        }
     228
    176229        if (error != 0)
    177230        {
    178             std::string origin;
    179             if (sourceFileInfo != NULL)
    180                 origin = " originating from " + sourceFileInfo_->filename;
    181             COUT(1) << "Error in Lua-script" << origin << ": " << lua_tostring(luaState_, -1) << std::endl;
    182             // return value is true (not nil!)
    183             lua_pushboolean(luaState_, 1);
    184         }
    185         if (lua_isnil(luaState_, -1))
    186         {
    187             // Nil return values cause problems
    188             lua_pop(luaState_, 1);
    189             lua_pushboolean(luaState_, 1);
    190         }
    191         // Push return value because it will get lost since the return value of this function is void
     231            // Push a nil return value
     232            lua_pushnil(luaState_);
     233        }
     234
     235        // Set return value to a global variable because we cannot return a table in this function
     236        // here. It would work for numbers, pointers and strings, but certainly not for Lua tables.
    192237        lua_setglobal(luaState_, "LuaStateReturnValue");
    193238
    194239        // Load the old info again
    195240        sourceFileInfo_ = oldSourceFileInfo;
     241
     242        return (error == 0);
    196243    }
    197244
     
    230277    }
    231278
     279    bool LuaState::usingIOConsole() const
     280    {
     281        return IOConsole::exists();
     282    }
     283
    232284#if LUA_VERSION_NUM != 501
    233285    const char * LuaState::lua_Chunkreader(lua_State *L, void *data, size_t *size)
  • code/branches/gamestate/src/libraries/core/LuaState.h

    r6627 r6660  
    7171        ~LuaState();
    7272
    73         void doFile(const std::string& filename); // tolua_export
    74         void doString(const std::string& code, const shared_ptr<ResourceInfo>& sourceFileInfo = shared_ptr<ResourceInfo>());
     73        bool doFile(const std::string& filename); // tolua_export
     74        bool doString(const std::string& code, const shared_ptr<ResourceInfo>& sourceFileInfo = shared_ptr<ResourceInfo>());
    7575
    76         void includeFile(const std::string& filename); // tolua_export
    77         void includeString(const std::string& code, const shared_ptr<ResourceInfo>& sourceFileInfo = shared_ptr<ResourceInfo>());
     76        bool includeFile(const std::string& filename); // tolua_export
     77        bool includeString(const std::string& code, const shared_ptr<ResourceInfo>& sourceFileInfo = shared_ptr<ResourceInfo>());
    7878
    7979        void luaPrint(const std::string& str); // tolua_export
     
    9292
    9393        Functor* createLuaFunctor(const std::string& code) { return new LuaFunctor(code, this); } // tolua_export
     94        //! Tells about whether IOConsole was activated. The Lua debugger only works with a normal console.
     95        bool usingIOConsole() const; // tolua_export
    9496
    9597        static bool addToluaInterface(int (*function)(lua_State*), const std::string& name);
Note: See TracChangeset for help on using the changeset viewer.