Files
WoWee/tools/framexml_compile_check.cpp
Kelsi 4d2c0b15b8 feat: build virtual Texture and FontString templates; run the compile check as a test
Twenty-two virtual regions sit at the top level of FrameXML — the dialog
button's normal, pushed and highlight art among them — and none was
emitted, so every button inheriting its art had none. They become
templates the same way a virtual frame does, and a region's inherits
replays one before its own attributes so what it states itself wins.

A FontString's inherits is ambiguous by design: usually a font object,
sometimes a virtual FontString, and the name alone does not say which.
The emitted line asks at runtime and falls back to SetFontObject.

The emitter also says so when it meets an element type it does not
build, because that failure is silence — minimap.xml produced nothing
whatever for exactly this reason and still loaded and still compiled.
framexml_compile_check is now a ctest target that reports those and
fails on a file that will not compile: 140 compile, 0 unbuilt.
2026-08-01 22:21:34 -07:00

76 lines
3.3 KiB
C++

// Does the Lua we generate from FrameXML actually compile?
//
// The unit tests check the shape of the output against cases someone thought
// of. This asks Lua itself about every real file, which is a different and
// harsher question — it found an empty function attribute emitting
// SetScript("X", ), and temporaries running into Lua's limit of 200 locals per
// function. Neither degrades: the whole chunk refuses to compile.
//
// Build (needs the project's lua51 built):
// g++ -std=c++20 -Iinclude -Iextern/lua-5.1.5/src \
// tools/framexml_compile_check.cpp src/ui/xml_parser.cpp \
// src/ui/framexml_emitter.cpp build/lib/liblua51.a -o /tmp/fxcheck
// /tmp/fxcheck Data/interface/framexml
// Emits every FrameXML file and asks Lua whether the result compiles.
extern "C" {
#include "lua.h"
#include "lauxlib.h"
}
#include "ui/xml_parser.hpp"
#include "ui/framexml_emitter.hpp"
#include <cstdio>
#include <filesystem>
#include <fstream>
#include <sstream>
#include <string>
int main(int argc, char** argv) {
// Run from the build with no argument and it looks where the game data
// normally sits, so this can be a test rather than something remembered.
const char* dir = (argc > 1) ? argv[1] : "Data/interface/framexml";
if (!std::filesystem::is_directory(dir)) {
printf("no FrameXML at %s; nothing to check\n", dir);
return 77; // ctest reads this as skipped, not passed.
}
lua_State* L = luaL_newstate();
int ok = 0, bad = 0, shown = 0, unparsed = 0, unbuilt = 0;
for (auto& e : std::filesystem::directory_iterator(dir)) {
if (e.path().extension() != ".xml") continue;
std::ifstream f(e.path()); std::stringstream ss; ss << f.rdbuf();
wowee::ui::XmlNode root; std::string err;
// Counted, not skipped. A file the reader cannot get through never
// reaches the compiler at all, so passing over it quietly reports a
// clean run on files that in fact never loaded.
if (!wowee::ui::parseXml(ss.str(), root, err)) {
++unparsed;
printf(" UNPARSED %-30s %s\n", e.path().filename().string().c_str(),
err.c_str());
continue;
}
auto r = wowee::ui::emitFrameXml(root);
for (const auto& w : r.warnings) {
if (w.find("not a known frame type") != std::string::npos) {
printf(" UNBUILT %-30s %s\n",
e.path().filename().string().c_str(), w.c_str());
++unbuilt;
}
}
if (r.lua.empty()) { ++ok; continue; }
std::string chunk = "local __WoweeTemplates={} "
"local function __WoweeMissingTemplate() end\n" + r.lua;
if (luaL_loadbuffer(L, chunk.c_str(), chunk.size(), "=chunk") == 0) { ++ok; }
else {
++bad;
if (shown++ < 6)
printf(" FAIL %-34s %s\n", e.path().filename().string().c_str(),
lua_tostring(L, -1));
}
lua_settop(L, 0);
}
printf("emitted Lua compiles: %d fails: %d unparsed XML: %d "
"unbuilt elements: %d\n", ok, bad, unparsed, unbuilt);
// A file that will not compile is lost whole, so this is a failure rather
// than a number to read past.
return (bad > 0 || unparsed > 0) ? 1 : 0;
}