#include "JetParser.h" #include "JetCodegen.h" #include #include #include #include #include namespace { std::string baseNameNoExt(const std::string &path) { size_t slash = path.find_last_of("/\\"); std::string base = (slash == std::string::npos) ? path : path.substr(slash + 1); size_t dot = base.find_last_of('.'); if (dot != std::string::npos) base = base.substr(0, dot); return base; } std::string sanitizeIdent(const std::string &s) { std::string r; for (char c : s) r += (std::isalnum((unsigned char)c) || c == '_') ? c : '_'; return r; } } int main(int argc, char **argv) { bool shared = false; std::vector pos; for (int i = 1; i < argc; ++i) { std::string a = argv[i]; if (a == "--shared") shared = true; else pos.push_back(a); } if (pos.size() < 2) { std::cerr << "usage: jetc [--shared] " << std::endl; std::cerr << " --shared emit a dlsym()-able entry point (see build-shared.sh)" << std::endl; std::cerr << " instead of a standalone main()." << std::endl; return 1; } const std::string &inputPath = pos[0]; const std::string &outputPath = pos[1]; std::ifstream in(inputPath); if (!in) { std::cerr << "jetc: cannot open " << inputPath << std::endl; return 1; } std::ostringstream ss; ss << in.rdbuf(); std::string src = ss.str(); // Skip a leading shebang line, mirroring jet-2.0.cpp's own data.goeol() // call (run before it constructs the top-level __jet tag) so a // "#!../jet-2.0" first line doesn't get compiled in as literal output. if (src.rfind("#!", 0) == 0) { size_t nl = src.find('\n'); src = (nl == std::string::npos) ? std::string() : src.substr(nl + 1); } try { jetc::Parser parser(src); auto nodes = parser.parseNodes(); jetc::Codegen codegen; // Symbol is derived from the input filename (not the output path) so // it stays stable and predictable for whatever builds and dlsym()'s // the resulting .so - unique per template, so multiple compiled // templates' .so's can coexist in one process even under // dlopen(..., RTLD_GLOBAL) instead of requiring isolated handles. std::string symbol = "jetc_render_" + sanitizeIdent(baseNameNoExt(inputPath)); std::string cpp = codegen.generate(nodes, std::string("compiled from ") + inputPath, shared, symbol); std::ofstream outFile(outputPath); outFile << cpp; outFile.close(); if (shared) std::cout << "jetc: wrote " << outputPath << " (entry symbol: " << symbol << ")" << std::endl; else std::cout << "jetc: wrote " << outputPath << std::endl; } catch (std::exception &e) { std::cerr << "jetc: " << e.what() << std::endl; return 1; } return 0; }