alecAbstraction Layer for Escape Codes |
git clone git://git.dimitrijedobrota.com/alec.git |
Log | Files | Refs | README | LICENSE | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING |
generator.cpp (4354B)
0 #include <cstring> 1 #include <fstream> 2 #include <iostream> 3 #include <set> 4 #include <span> 5 #include <string> 6 #include <vector> 7 8 #include "generator.h" 9 10 #include <cemplate/cemplate.hpp> 11 12 #include "driver.hpp" 13 14 namespace alec 15 { 16 17 extern std::vector<record> records; // NOLINT 18 extern std::vector<std::string> epilogue; // NOLINT 19 extern std::vector<std::string> prologue; // NOLINT 20 21 } // namespace alec 22 23 namespace 24 { 25 26 auto generate_dupes() 27 { 28 std::set<std::string> dupes; 29 std::set<std::string> seen; 30 for (const auto& record : alec::records) { 31 const auto [_, inserted] = seen.insert(record.name); 32 if (!inserted) { 33 dupes.insert(record.name); 34 } 35 } 36 return dupes; 37 } 38 39 void generate_variables() 40 { 41 using namespace cemplate; // NOLINT 42 43 Program prog(std::cout); 44 45 prog.comment("Template compile-time variables\n"); 46 prog.comment("Forward-declare templates\n"); 47 48 const auto dupes = generate_dupes(); 49 for (const auto& dup : dupes) { 50 prog.template_decl({"auto... val"}); 51 prog.declaration("static const char* const", dup + "_v", string("")); 52 prog.line_empty(); 53 } 54 55 prog.comment("Template specializations\n"); 56 for (const auto& record : alec::records) { 57 if (record.recipe.empty()) { // comment 58 std::cout << record.name << '\n'; 59 continue; 60 } 61 62 std::vector<std::string> params; 63 params.reserve(record.args.size()); 64 for (const auto& arg : record.args) { 65 params.emplace_back(arg.substr(arg.find(' ') + 1)); 66 } 67 68 if (!record.args.empty()) { 69 prog.template_decl(record.args); 70 } 71 72 if (!record.rules.empty()) { 73 prog.require(join(std::begin(params), 74 std::end(params), 75 " && ", 76 [&](const auto& param) 77 { 78 return join( 79 std::begin(record.rules), 80 std::end(record.rules), 81 " && ", 82 [&](const auto& rule) 83 { return template_def(rule + "_v", {param}); }); 84 })); 85 } 86 87 const auto var = record.name + "_v"; 88 89 const auto type = 90 dupes.contains(record.name) ? template_def(var, params) : var; 91 92 const auto* temp = !record.recipe.empty() && record.recipe[0][0] == '"' 93 ? "details::escape_literal" 94 : "details::escape"; 95 96 prog.declaration( 97 "static constexpr auto", type, template_def(temp, record.recipe)); 98 99 prog.line_empty(); 100 } 101 } 102 103 void generate_functions() 104 { 105 using namespace cemplate; // NOLINT 106 107 Program prog(std::cout); 108 109 prog.comment("Run-time functions\n"); 110 for (const auto& record : alec::records) { 111 if (record.recipe.empty()) { // comment 112 std::cout << record.name << '\n'; 113 continue; 114 } 115 116 std::vector<std::string> params; 117 params.reserve(record.args.size()); 118 for (const auto& arg : record.args) { 119 params.emplace_back(arg.substr(arg.find(' ') + 1)); 120 } 121 122 prog.function_open(record.name, "static constexpr auto", record.args); 123 124 if (!record.rules.empty()) { 125 for (const auto& param : params) { 126 prog.call( 127 "assert", 128 join(std::begin(record.rules), 129 std::end(record.rules), 130 " && ", 131 [&](const std::string& rule) { return call(rule, {param}); })); 132 } 133 } 134 135 if (record.args.empty()) { 136 prog.ret(record.name + "_v"); 137 } else { 138 prog.ret(call("details::helper::make", record.recipe)); 139 } 140 141 prog.function_close(record.name); 142 } 143 } 144 145 } // namespace 146 147 int main(int argc, char* argv[]) 148 { 149 const std::span args(argv, static_cast<std::size_t>(argc)); 150 151 const bool debug = argc > 1 && std::strcmp(args[1], "--debug") == 0; 152 std::ifstream ifile; 153 if (argc != 1) { 154 ifile.open(args[!debug ? 1 : 2]); 155 } 156 157 using namespace alec; // NOLINT 158 159 driver drv = argc == 1 ? driver(std::cin, debug) : driver(ifile, debug); 160 parser parser(drv, debug); 161 const int res = parser(); 162 163 if (res != 0) { 164 std::cerr << "Parser error"; 165 return -1; 166 } 167 168 // print prologue section 169 for (const auto& line : prologue) { 170 std::cout << line; 171 } 172 173 generate_variables(); 174 generate_functions(); 175 176 // print epilogue section 177 for (const auto& line : epilogue) { 178 std::cout << line; 179 } 180 }