diff --git a/aegisub/src/auto4_lua.cpp b/aegisub/src/auto4_lua.cpp index 187b0095c..409d462f8 100644 --- a/aegisub/src/auto4_lua.cpp +++ b/aegisub/src/auto4_lua.cpp @@ -605,6 +605,43 @@ namespace Automation4 { return lua_gettop(L) - pretop; } + static int moon_line(lua_State *L, int lua_line, std::string const& file) + { + if (luaL_dostring(L, "return require 'moonscript.line_tables'")) { + lua_pop(L, 1); // pop error message + return lua_line; + } + + push_value(L, file); + lua_rawget(L, -2); + + if (!lua_istable(L, -1)) { + lua_pop(L, 2); + return lua_line; + } + + lua_rawgeti(L, -1, lua_line); + if (!lua_isnumber(L, -1)) { + lua_pop(L, 3); + return lua_line; + } + + auto char_pos = static_cast(lua_tonumber(L, -1)); + lua_pop(L, 3); + + // The moonscript line tables give us a character offset into the file, + // so now we need to map that to a line number + lua_getfield(L, LUA_REGISTRYINDEX, ("raw moonscript: " + file).c_str()); + if (!lua_isstring(L, -1)) { + lua_pop(L, 1); + return lua_line; + } + + size_t moon_len; + auto moon = lua_tolstring(L, -1, &moon_len); + return std::count(moon, moon + std::min(moon_len, char_pos), '\n') + 1; + } + static int add_stack_trace(lua_State *L) { int level = 1; @@ -635,9 +672,16 @@ namespace Automation4 { if (ar.what[0] == 't') frames.emplace_back("(tail call)"); else { + bool is_moon = false; std::string file = ar.source; if (file == "=[C]") file = ""; + else if (boost::ends_with(file, ".moon")) + is_moon = true; + + auto real_line = [&](int line) { + return is_moon ? moon_line(L, line, file) : line; + }; std::string function = ar.name ? ar.name : ""; if (*ar.what == 'm') @@ -645,9 +689,9 @@ namespace Automation4 { else if (*ar.what == 'C') function = '?'; else if (!*ar.namewhat) - function = str(boost::format("") % ar.linedefined % ar.lastlinedefined); + function = str(boost::format("") % real_line(ar.linedefined) % real_line(ar.lastlinedefined - 1)); - frames.emplace_back(str(boost::format(" File \"%s\", line %d\n%s") % file % ar.currentline % function)); + frames.emplace_back(str(boost::format(" File \"%s\", line %d\n%s") % file % real_line(ar.currentline) % function)); } } diff --git a/aegisub/src/auto4_lua_scriptreader.cpp b/aegisub/src/auto4_lua_scriptreader.cpp index 265f8cbd2..08cc47144 100644 --- a/aegisub/src/auto4_lua_scriptreader.cpp +++ b/aegisub/src/auto4_lua_scriptreader.cpp @@ -21,8 +21,9 @@ #include "auto4_lua_scriptreader.h" +#include "auto4_lua_utils.h" + #include -#include #include #include @@ -53,6 +54,11 @@ namespace Automation4 { if (!agi::fs::HasExtension(filename, "moon")) return luaL_loadbuffer(L, &buff[0], buff.size(), filename.string().c_str()) == 0; + // Save the text we'll be loading for the line number rewriting in the + // error handling + push_value(L, buff); + lua_setfield(L, LUA_REGISTRYINDEX, ("raw moonscript: " + filename.string()).c_str()); + // We have a MoonScript file, so we need to load it with that // It might be nice to have a dedicated lua state for compiling // MoonScript to Lua