|
22 | 22 | #include <sstream> |
23 | 23 |
|
24 | 24 | #include "piece.h" |
| 25 | +#include "parser.h" |
25 | 26 | #include "variant.h" |
26 | 27 |
|
27 | 28 | using std::string; |
@@ -86,6 +87,83 @@ void VariantMap::init() { |
86 | 87 | add("spell-chess", spell_chess_variant()); |
87 | 88 | } |
88 | 89 |
|
| 90 | +/// VariantMap::parse_istream reads variants from an INI-style configuration input stream. |
| 91 | + |
| 92 | +template <bool DoCheck> |
| 93 | +void VariantMap::parse_istream(std::istream& file) { |
| 94 | + std::string variant, variant_template, key, value, input; |
| 95 | + while (file.peek() != '[' && std::getline(file, input)) {} |
| 96 | + |
| 97 | + std::vector<std::string> varsToErase = {}; |
| 98 | + while (file.get() && std::getline(std::getline(file, variant, ']'), input)) |
| 99 | + { |
| 100 | + // Extract variant template, if specified |
| 101 | + if (!std::getline(std::getline(std::stringstream(variant), variant, ':'), variant_template)) |
| 102 | + variant_template = ""; |
| 103 | + |
| 104 | + // Read variant rules |
| 105 | + Config attribs = {}; |
| 106 | + while (file.peek() != '[' && std::getline(file, input)) |
| 107 | + { |
| 108 | + if (!input.empty() && input.back() == '\r') |
| 109 | + input.pop_back(); |
| 110 | + std::stringstream ss(input); |
| 111 | + if (ss.peek() != ';' && ss.peek() != '#') |
| 112 | + { |
| 113 | + if (DoCheck && !input.empty() && input.find('=') == std::string::npos) |
| 114 | + std::cerr << "Invalid syntax: '" << input << "'." << std::endl; |
| 115 | + if (std::getline(std::getline(ss, key, '=') >> std::ws, value) && !key.empty()) |
| 116 | + attribs[key.erase(key.find_last_not_of(" ") + 1)] = value; |
| 117 | + } |
| 118 | + } |
| 119 | + |
| 120 | + // Create variant |
| 121 | + if (variants.find(variant) != variants.end()) |
| 122 | + std::cerr << "Variant '" << variant << "' already exists." << std::endl; |
| 123 | + else if (!variant_template.empty() && variants.find(variant_template) == variants.end()) |
| 124 | + std::cerr << "Variant template '" << variant_template << "' does not exist." << std::endl; |
| 125 | + else |
| 126 | + { |
| 127 | + if (DoCheck) |
| 128 | + std::cerr << "Parsing variant: " << variant << std::endl; |
| 129 | + Variant* v = !variant_template.empty() ? VariantParser<DoCheck>(attribs).parse((new Variant(*variants.find(variant_template)->second))->init()) |
| 130 | + : VariantParser<DoCheck>(attribs).parse(); |
| 131 | + if (v->maxFile <= FILE_MAX && v->maxRank <= RANK_MAX) |
| 132 | + { |
| 133 | + add(variant, v); |
| 134 | + // In order to allow inheritance, we need to temporarily add configured variants |
| 135 | + // even when only checking them, but we remove them later after parsing is finished. |
| 136 | + if (DoCheck) |
| 137 | + varsToErase.push_back(variant); |
| 138 | + } |
| 139 | + else |
| 140 | + delete v; |
| 141 | + } |
| 142 | + } |
| 143 | + // Clean up temporary variants |
| 144 | + for (std::string tempVar : varsToErase) |
| 145 | + { |
| 146 | + delete variants[tempVar]; |
| 147 | + variants.erase(tempVar); |
| 148 | + } |
| 149 | +} |
| 150 | + |
| 151 | +/// VariantMap::parse reads variants from an INI-style configuration file. |
| 152 | + |
| 153 | +template <bool DoCheck> |
| 154 | +void VariantMap::parse(std::string path) { |
| 155 | + if (path.empty() || path == "<empty>") |
| 156 | + return; |
| 157 | + std::ifstream file(path); |
| 158 | + if (!file.is_open()) |
| 159 | + { |
| 160 | + std::cerr << "Unable to open file " << path << std::endl; |
| 161 | + return; |
| 162 | + } |
| 163 | + parse_istream<DoCheck>(file); |
| 164 | + file.close(); |
| 165 | +} |
| 166 | + |
89 | 167 | // Pre-calculate derived properties |
90 | 168 | Variant* Variant::conclude() { |
91 | 169 | // Enforce consistency to allow runtime optimizations |
@@ -300,7 +378,7 @@ std::vector<std::string> VariantMap::get_keys() { |
300 | 378 | // VariantPath parsing entry points. |
301 | 379 | template void VariantMap::parse_istream<true>(std::istream&); |
302 | 380 | template void VariantMap::parse_istream<false>(std::istream&); |
303 | | -template void VariantMap::parse<true>(const std::string&); |
304 | | -template void VariantMap::parse<false>(const std::string&); |
| 381 | +template void VariantMap::parse<true>(std::string); |
| 382 | +template void VariantMap::parse<false>(std::string); |
305 | 383 |
|
306 | 384 | } // namespace Stockfish |
0 commit comments