From 29e85c811ddbf45cc8cb830012abefce8a92009a Mon Sep 17 00:00:00 2001 From: dshaligram Date: Sun, 24 Jun 2007 19:38:20 +0000 Subject: Hackily rewrite Lua chunk errors to reflect line numbers from the original .des file so that level-designers can find the lines that are causing the problem. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@1641 c06c8d41-db1a-0410-9941-cceddc491573 --- crawl-ref/source/clua.cc | 38 +++++++++++++++++++ crawl-ref/source/dat/clua/dungeon.lua | 4 +- crawl-ref/source/luadgn.cc | 71 +++++++++++++++++++++++++++++++++-- crawl-ref/source/luadgn.h | 8 +++- crawl-ref/source/mapdef.cc | 27 ++++++------- crawl-ref/source/mapdef.h | 3 +- crawl-ref/source/util/levcomp.ypp | 7 +++- 7 files changed, 131 insertions(+), 27 deletions(-) (limited to 'crawl-ref/source') diff --git a/crawl-ref/source/clua.cc b/crawl-ref/source/clua.cc index 6f891072df..7e2c43a98a 100644 --- a/crawl-ref/source/clua.cc +++ b/crawl-ref/source/clua.cc @@ -1815,6 +1815,41 @@ static int crawl_split(lua_State *ls) return (1); } +LUARET1(crawl_game_started, boolean, crawl_state.need_save) + +static int crawl_err_trace(lua_State *ls) +{ + const int nargs = lua_gettop(ls); + const int err = lua_pcall(ls, nargs - 1, LUA_MULTRET, 0); + + if (err) + { + // This code from lua.c:traceback() (mostly) + const char *errs = lua_tostring(ls, 1); + std::string errstr = errs? errs : ""; + lua_getfield(ls, LUA_GLOBALSINDEX, "debug"); + if (!lua_istable(ls, -1)) + { + lua_pop(ls, 1); + return lua_error(ls); + } + lua_getfield(ls, -1, "traceback"); + if (!lua_isfunction(ls, -1)) + { + lua_pop(ls, 2); + return lua_error(ls); + } + lua_pushvalue(ls, 1); + lua_pushinteger(ls, 2); // Skip crawl_err_trace and traceback. + lua_call(ls, 2, 1); + + // What's on top should be the error. + lua_error(ls); + } + + return (lua_gettop(ls)); +} + static const struct luaL_reg crawl_lib[] = { { "mpr", crawl_mpr }, @@ -1837,6 +1872,9 @@ static const struct luaL_reg crawl_lib[] = { "message_filter", crawl_message_filter }, { "trim", crawl_trim }, { "split", crawl_split }, + { "game_started", crawl_game_started }, + { "err_trace", crawl_err_trace }, + { NULL, NULL }, }; diff --git a/crawl-ref/source/dat/clua/dungeon.lua b/crawl-ref/source/dat/clua/dungeon.lua index c25e06c4df..28084beaa8 100644 --- a/crawl-ref/source/dat/clua/dungeon.lua +++ b/crawl-ref/source/dat/clua/dungeon.lua @@ -11,7 +11,7 @@ function dgn_map_meta_wrap(obj, tab) local meta = { } for fn, val in pairs(tab) do meta[fn] = function (...) - return val(obj, ...) + return crawl.err_trace(val, obj, ...) end end meta.wrapped_instance = obj @@ -38,4 +38,4 @@ function dgn_run_map(prelude, main) -- calls. return env end -end \ No newline at end of file +end diff --git a/crawl-ref/source/luadgn.cc b/crawl-ref/source/luadgn.cc index 2381dcfa97..f0dbee15bc 100644 --- a/crawl-ref/source/luadgn.cc +++ b/crawl-ref/source/luadgn.cc @@ -38,8 +38,8 @@ static int dlua_stringtable(lua_State *ls, const std::vector &s) /////////////////////////////////////////////////////////////////////////// // dlua_chunk -dlua_chunk::dlua_chunk() - : file(), chunk(), first(-1), last(-1), error() +dlua_chunk::dlua_chunk(const std::string &_context) + : file(), chunk(), context(_context), first(-1), last(-1), error() { clear(); } @@ -63,7 +63,8 @@ void dlua_chunk::add(int line, const std::string &s) first = line; if (line != last && last != -1) - chunk += "\n"; + while (last++ < line) + chunk += '\n'; chunk += " "; chunk += s; @@ -86,7 +87,7 @@ int dlua_chunk::load(CLua *interp) if (trimmed_string(chunk).empty()) return (-1000); return check_op(interp, - interp->loadstring(chunk.c_str(), "dlua_chunk")); + interp->loadstring(chunk.c_str(), context.c_str())); } int dlua_chunk::load_call(CLua *interp, const char *fn) @@ -110,6 +111,67 @@ bool dlua_chunk::empty() const return trimmed_string(chunk).empty(); } +bool dlua_chunk::rewrite_chunk_errors(std::string &s) const +{ + if (s.find(context) == std::string::npos) + return (false); + + // Our chunk is mentioned, go back through and rewrite lines. + std::vector lines = split_string("\n", s); + std::string newmsg = lines[0]; + bool wrote_prefix = false; + for (int i = 2, size = lines.size() - 1; i < size; ++i) + { + const std::string &st = lines[i]; + if (st.find(context) != std::string::npos) + { + if (!wrote_prefix) + { + newmsg = get_chunk_prefix(st) + ": " + newmsg; + wrote_prefix = true; + } + else + newmsg += "\n" + rewrite_chunk_prefix(st); + } + } + s = newmsg; + return (true); +} + +std::string dlua_chunk::rewrite_chunk_prefix(const std::string &line) const +{ + std::string s = line; + const std::string contextm = "[string \"" + context + "\"]:"; + const std::string::size_type ps = s.find(contextm); + if (ps == std::string::npos) + return (s); + + std::string::size_type pe = s.find(':', ps + contextm.length()); + if (pe != std::string::npos) + { + const std::string::size_type lns = ps + contextm.length(); + const std::string line_num = s.substr(lns, pe - lns); + const int lnum = atoi(line_num.c_str()); + s = s.substr(0, lns) + make_stringf("%d", lnum + first - 1) + + s.substr(pe); + } + + return s.substr(0, ps) + (file.empty()? context : file) + ":" + + s.substr(ps + contextm.length()); +} + +std::string dlua_chunk::get_chunk_prefix(const std::string &sorig) const +{ + std::string s = rewrite_chunk_prefix(sorig); + const std::string::size_type cpos = s.find(':'); + if (cpos == std::string::npos) + return (s); + const std::string::size_type cnpos = s.find(':', cpos + 1); + if (cnpos == std::string::npos) + return (s); + return s.substr(0, cnpos); +} + /////////////////////////////////////////////////////////////////////////// // Lua dungeon bindings (in the dgn table). @@ -510,6 +572,7 @@ static const struct luaL_reg dgn_lib[] = void init_dungeon_lua() { dlua.execfile("clua/dungeon.lua"); + luaopen_debug(dlua); luaL_newmetatable(dlua, MAP_METATABLE); lua_pop(dlua, 1); luaL_openlib(dlua, "dgn", dgn_lib, 0); diff --git a/crawl-ref/source/luadgn.h b/crawl-ref/source/luadgn.h index 199939dad2..f8b272f544 100644 --- a/crawl-ref/source/luadgn.h +++ b/crawl-ref/source/luadgn.h @@ -18,16 +18,19 @@ class dlua_chunk private: std::string file; std::string chunk; + std::string context; int first, last; // First and last lines of the original source. private: int check_op(CLua *, int); + std::string rewrite_chunk_prefix(const std::string &line) const; + std::string get_chunk_prefix(const std::string &s) const; public: std::string error; public: - dlua_chunk(); + dlua_chunk(const std::string &_context = "dlua_chunk"); void clear(); void add(int line, const std::string &line); void set_chunk(const std::string &s); @@ -38,7 +41,8 @@ public: const std::string &lua_string() const { return chunk; } std::string orig_error() const; - + bool rewrite_chunk_errors(std::string &err) const; + bool empty() const; }; diff --git a/crawl-ref/source/mapdef.cc b/crawl-ref/source/mapdef.cc index 8a4c40ff39..5323c421a0 100644 --- a/crawl-ref/source/mapdef.cc +++ b/crawl-ref/source/mapdef.cc @@ -813,7 +813,7 @@ std::vector map_lines::get_subst_strings() const map_def::map_def() : name(), tags(), place(), depths(), orient(), chance(), - map(), mons(), items(), keyspecs(), prelude(), main(), + map(), mons(), items(), keyspecs(), prelude("dlprelude"), main("dlmain"), index_only(false), cache_offset(0L) { init(); @@ -937,18 +937,6 @@ void map_def::set_file(const std::string &s) file = get_base_filename(s); } -void map_def::run_strip_prelude() -{ - run_lua(false); - prelude.clear(); -} - -void map_def::strip_main() -{ - main.clear(); - index_only = true; -} - std::string map_def::run_lua(bool run_main) { dlua.callfn("dgn_set_map", "m", this); @@ -970,14 +958,23 @@ std::string map_def::run_lua(bool run_main) } if (!dlua.callfn("dgn_run_map", 2, 0)) - return (dlua.error); - + return rewrite_chunk_errors(dlua.error); + // Clear the map setting. dlua.callfn("dgn_set_map", 0, 0); return (dlua.error); } +std::string map_def::rewrite_chunk_errors(const std::string &s) const +{ + std::string res = s; + if (prelude.rewrite_chunk_errors(res)) + return (res); + main.rewrite_chunk_errors(res); + return (res); +} + std::string map_def::validate() { std::string err = run_lua(true); diff --git a/crawl-ref/source/mapdef.h b/crawl-ref/source/mapdef.h index 94bad0bc8f..c2ef6e897d 100644 --- a/crawl-ref/source/mapdef.h +++ b/crawl-ref/source/mapdef.h @@ -437,8 +437,6 @@ public: void set_file(const std::string &s); std::string run_lua(bool skip_main); - void run_strip_prelude(); - void strip_main(); std::string validate(); @@ -481,6 +479,7 @@ public: private: void write_depth_ranges(FILE *) const; void read_depth_ranges(FILE *); + std::string rewrite_chunk_errors(const std::string &s) const; std::string add_key_field( const std::string &s, diff --git a/crawl-ref/source/util/levcomp.ypp b/crawl-ref/source/util/levcomp.ypp index bedd60c7ba..daffae671c 100644 --- a/crawl-ref/source/util/levcomp.ypp +++ b/crawl-ref/source/util/levcomp.ypp @@ -32,7 +32,10 @@ static map_load_info_t loaded_maps; void yyerror(const char *e) { - fprintf(stderr, "%s:%d: %s\n", lc_desfile.c_str(), yylineno, e); + if (strstr(e, lc_desfile.c_str()) == e) + fprintf(stderr, "%s\n", e); + else + fprintf(stderr, "%s:%d: %s\n", lc_desfile.c_str(), yylineno, e); // Bail bail bail. end(1); } @@ -100,13 +103,13 @@ defdepth : DEFAULT_DEPTH STRING level : name metalines map_def metalines { + lc_map.set_file(lc_desfile); std::string err = lc_map.validate(); if (!err.empty()) yyerror(err.c_str()); if (!lc_map.has_depth() && !lc_default_depths.empty()) lc_map.add_depths(lc_default_depths.begin(), lc_default_depths.end()); - lc_map.set_file(lc_desfile); add_parsed_map(lc_map); } ; -- cgit v1.2.3-54-g00ecf