#include "httplib.h" #include "peglib.h" #include #include using namespace httplib; using namespace std; static string indexHTML = R"( PEG Playground
  • Grammar:
  • Valid
{{syntax}}
  • Code:
  • Valid
{{source}}

        

        
)"; function makeJSONFormatter(string& json) { auto init = make_shared(true); return [&json, init](size_t ln, size_t col, const string& msg) mutable { if (!init) { json += ","; } json += "{"; json += R"("ln":)" + to_string(ln) + ","; json += R"("col":)" + to_string(col) + ","; json += R"("msg":")" + msg + R"(")"; json += "}"; *init = false; }; } bool parse_grammar(const string& text, peg::parser& peg, string& json) { peg.log = makeJSONFormatter(json); json += "["; auto ret = peg.load_grammar(text.data(), text.size()); json += "]"; return ret; } bool parse_code(const string& text, peg::parser& peg, string& json, shared_ptr& ast) { peg.enable_ast(); peg.log = makeJSONFormatter(json); json += "["; auto ret = peg.parse_n(text.data(), text.size(), ast); json += "]"; return ret; } string replace_all(const string& str, const char* from, const char* to) { string ret; ret.reserve(str.length()); size_t from_len = 0; while (from[from_len]) { from_len++; } size_t start_pos = 0, pos; while ((pos = str.find(from, start_pos)) != string::npos) { ret += str.substr(start_pos, pos - start_pos); ret += to; pos += from_len; start_pos = pos; } ret += str.substr(start_pos); return ret; } int run_server(int port, const vector& syntax, const vector& source) { Server svr; svr.get("/", [&](const Request& /*req*/, Response& res) { indexHTML = replace_all(indexHTML, "{{syntax}}", string(syntax.data(), syntax.size()).c_str()); indexHTML = replace_all(indexHTML, "{{source}}", string(source.data(), source.size()).c_str()); res.set_content(indexHTML, "text/html"); }); svr.post("/parse", [](const Request& req, Response& res) { const auto& grammarText = req.params.at("grammar"); string grammarResult; string codeResult; string astResult; string astResultOptimized; peg::parser peg; auto ret = parse_grammar(grammarText, peg, grammarResult); if (ret && peg) { const auto& codeText = req.params.at("code"); shared_ptr ast; if (parse_code(codeText, peg, codeResult, ast)) { astResult = peg::ast_to_s(ast); astResult = replace_all(astResult, "\n", "\\n"); astResultOptimized = peg::ast_to_s(peg::AstOptimizer(true).optimize(ast)); astResultOptimized = replace_all(astResultOptimized, "\n", "\\n"); } } string json; json += "{"; json += "\"grammar\":" + grammarResult; if (!codeResult.empty()) { json += ",\"code\":" + codeResult; json += ",\"ast\":\"" + astResult + "\""; json += ",\"astOptimized\":\"" + astResultOptimized + "\""; } json += "}"; res.set_content(json, "application/json"); }); svr.set_error_handler([](const Request& /*req*/, Response& res) { const char* fmt = "

Error Status: %d

"; char buf[BUFSIZ]; snprintf(buf, sizeof(buf), fmt, res.status); res.set_content(buf, "text/html"); }); cerr << "Server running at http://localhost:" << port << "/" << endl; svr.listen("localhost", port); return 0; } // vim: et ts=4 sw=4 cin cino={1s ff=unix