#ifndef __JetCodegen_h__ #define __JetCodegen_h__ #include "JetAST.h" #include #include namespace jetc { // Emits a standalone .cpp translation unit that renders a compiled JET // template. The static tag/text structure becomes real C++ control flow; // anything genuinely dynamic (variable values, expr/value comparisons, // loop bounds) still calls into the existing JetCore/CoreUtils runtime // (Tag::getVariable/resolveKeyword/assignVariable, jet::Operand) exactly // as the interpreter does - compiling doesn't try to eliminate that, only // the repeated re-parsing of the template's own structure. class Codegen { public: // sharedMode == false (default): emits a static jetc_render() plus a // main() that runs it once, catches coreutils::Exception, and writes // the result to stdout - the existing CGI-style standalone program. // // sharedMode == true: emits no main() at all. Instead the render // logic is exported as `extern "C" void (jet::Global // &global, coreutils::MString &out)`, meant to be built into a .so // (see build-shared.sh) and dlsym()'d by a long-running host server - // one call renders one request into the caller-owned `out`, using // whatever Global the host passes in (its lifecycle, cgi/session // setup etc. is entirely the host's business, not this module's). // extern "C" only affects name mangling here, not the parameter // types - both sides are compiled from the same CoreUtils/JetCore // headers with the same toolchain, so passing C++ class types (and // letting coreutils::Exception propagate to the caller) across the // dlopen() boundary is safe; this is a same-ABI plugin boundary, not // a foreign C ABI one. entrySymbol should be unique per compiled // template (see jetc.cpp) so multiple .so's can coexist even if a // host ever dlopen()s them RTLD_GLOBAL instead of keeping separate // handles. std::string generate(const std::vector &top, const std::string &sourceFileComment, bool sharedMode = false, const std::string &entrySymbol = "jetc_render"); private: std::ostringstream out; size_t nextId = 0; std::string id(const std::string &prefix) { return prefix + std::to_string(nextId++) + "_"; } void emitBody(const std::vector &nodes, int indent); void emitNode(const NodePtr &n, int indent); static std::string ind(int indent); static std::string cstr(const std::string &raw); // C++ string-literal escape static const char *staticTypeOp(const std::string &type, const char *rcVar); }; } #endif