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