30 wml_tag::wml_tag(
const std::string& name,
int min,
int max,
const std::string& super,
bool any)
35 , fuzzy_(name.find_first_of(
"*?") != std::string::npos)
41 : name_(cfg[
"name"].str())
42 , min_(cfg[
"min"].to_int())
43 , max_(cfg[
"max"].str() ==
"infinite" ? -1 : cfg[
"max"].to_int(1))
44 , min_children_(cfg[
"min_tags"].to_int())
45 , max_children_(cfg[
"max_tags"].str() ==
"infinite" ? -1 : cfg[
"max_tags"].to_int(-1))
52 , fuzzy_(name_.find_first_of(
"*?+") != std::string::npos)
53 , any_tag_(cfg[
"any_tag"].to_bool())
56 max_ = std::numeric_limits<int>::max();
63 super_ = cfg[
"super"].str();
77 std::string link_name = link[
"name"].str();
97 std::istringstream
i(
s);
105 std::istringstream
i(
s);
113 std::string::size_type pos_last = link.rfind(
'/');
115 std::string name_link = link.substr(pos_last + 1, link.length());
116 links_.emplace(name_link, link);
121 auto visited = std::vector<const wml_tag*>();
122 return find_key(name, match, ignore_super, visited);
128 if(
std::find(visited.begin(), visited.end(),
this) != visited.end()) {
132 visited.push_back(
this);
137 if(cond.matches(match)) {
139 if(
auto key = cond.find_key(name, match,
true)) {
145 const auto it_keys =
keys_.find(name);
146 if(it_keys !=
keys_.end()) {
147 return &(it_keys->second);
150 key_map::const_iterator it_fuzzy = std::find_if(
keys_.begin(),
keys_.end(), [&name](
const key_map::value_type& key){
151 if(!key.second.is_fuzzy()) {
156 if(it_fuzzy != keys_.end()) {
157 return &(it_fuzzy->second);
161 for(
auto& cond : conditions_) {
162 if(cond.matches(match)) {
164 if(
auto key = cond.find_key(name, match,
false, visited)) {
169 for(
auto& [
_, super_tag] : super_refs_) {
170 if(
const wml_key* found_key = super_tag->find_key(name, match,
false, visited)) {
179 const std::string* wml_tag::find_link(
const std::string& name)
const
181 const auto it_links = links_.find(name);
182 if(it_links != links_.end()) {
183 return &(it_links->second);
189 const wml_tag* wml_tag::find_tag(
const std::string& fullpath,
const wml_tag& root,
const config& match,
bool ignore_super)
const
191 auto visited = std::vector<const wml_tag*>();
192 return find_tag(fullpath, root, match, ignore_super, visited);
195 const wml_tag* wml_tag::find_tag(
const std::string& fullpath,
const wml_tag& root,
const config& match,
bool ignore_super, std::vector<const wml_tag*>& visited)
const
198 if(
std::find(visited.begin(), visited.end(),
this) != visited.end()) {
202 visited.push_back(
this);
204 if(fullpath.empty()) {
208 std::string::size_type pos = fullpath.find(
'/');
210 std::string next_path;
212 if(pos != std::string::npos) {
213 name = fullpath.substr(0, pos);
214 next_path = fullpath.substr(pos + 1, fullpath.length());
221 for(
auto& cond : conditions_) {
222 if(cond.matches(match)) {
224 if(
auto tag = cond.find_tag(fullpath, root, match,
true)) {
230 const auto it_tags = tags_.find(name);
231 if(it_tags != tags_.end()) {
232 if(next_path.empty()) {
233 return &(it_tags->second);
235 return it_tags->second.find_tag(next_path, root, match,
false, visited);
239 const auto it_links = links_.find(name);
240 if(it_links != links_.end()) {
242 return root.
find_tag(it_links->second +
"/" + next_path, root, match,
false);
245 const auto it_fuzzy = std::find_if(tags_.begin(), tags_.end(), [&name](
const tag_map::value_type&
tag) {
246 if(!tag.second.fuzzy_) {
251 if(it_fuzzy != tags_.end()) {
252 if(next_path.empty()) {
253 return &(it_fuzzy->second);
255 return it_tags->second.
find_tag(next_path, root, match,
false, visited);
260 for(
auto& cond : conditions_) {
261 if(cond.matches(match)) {
263 if(
auto tag = cond.find_tag(fullpath, root, match,
false, visited)) {
268 for(
auto& [
_, super_tag] : super_refs_) {
269 if(
const wml_tag* found_tag = super_tag->find_tag(fullpath, root, match,
false, visited)) {
284 for(
auto&
tag : tags_) {
285 tag.second.expand(root);
286 tag.second.expand_all(root);
288 for(
auto& cond : conditions_) {
290 cond.expand_all(root);
294 void wml_tag::remove_keys_by_type(
const std::string&
type)
296 auto i = keys_.begin();
297 while(
i != keys_.end()) {
298 if(
i->second.get_type() ==
type) {
305 for(
auto&
tag : tags_) {
306 tag.second.remove_keys_by_type(
type);
310 void wml_tag::printl(std::ostream& os,
int level,
int step)
313 for(
int j = 0; j <
level; j++) {
318 <<
s <<
" name=\"" << name_ <<
"\"\n"
319 <<
s <<
" min=\"" << min_ <<
"\"\n"
320 <<
s <<
" max=\"" << max_ <<
"\"\n";
322 if(!super_.empty()) {
323 os <<
s <<
" super=\"" << super_ <<
"\"\n";
326 for(
auto&
tag : tags_) {
327 tag.second.printl(os,
level + step, step);
330 for(
auto& link : links_) {
334 <<
" name=\"" << link.second <<
"\"\n"
339 for(
auto& key : keys_) {
340 key.second.print(os,
level + step);
345 os <<
s <<
"[/tag]\n";
351 auto it = tags_.find(
tag.name_);
353 if(it == tags_.end()) {
354 tags_.emplace(
tag.name_,
tag);
356 it->second.set_min(
tag.min_);
357 it->second.set_max(
tag.max_);
358 it->second.add_tags(
tag.tags_);
359 it->second.add_keys(
tag.keys_);
360 it->second.add_links(
tag.links_);
364 links_.erase(
tag.get_name());
368 std::string::size_type pos =
path.find(
'/');
369 std::string name =
path.substr(0, pos);
370 std::string next_path =
path.substr(pos + 1,
path.length());
372 auto it_links = links_.find(name);
373 if(it_links != links_.end()) {
374 root.
add_tag(it_links->second +
"/" + next_path,
tag, root);
377 auto it_tags = tags_.find(name);
378 if(it_tags == tags_.end()) {
382 tags_.emplace(name, subtag);
386 it_tags->second.add_tag(next_path,
tag, root);
391 conditions_.insert(conditions_.end(), list.begin(), list.end());
399 if(super_tag !=
this) {
400 super_refs_.emplace(super, super_tag);
406 void wml_tag::add_switch(
const config& switch_cfg)
409 const std::string key = switch_cfg[
"key"];
410 bool allow_missing =
false;
411 for(
const auto& case_cfg : switch_cfg.
child_range(
"case")) {
412 if(case_cfg.has_attribute(
"value")) {
415 for(
const auto& value : values) {
423 default_cfg.
add_child(
"not")[key] = value;
425 if(!allow_missing && case_cfg[
"trigger_if_missing"].to_bool()) {
427 missing_filter[
"glob_on_" + key] =
"*";
428 allow_missing =
true;
430 conditions_.emplace_back(case_cfg, filter);
433 conditions_.emplace_back(case_cfg,
config());
435 const std::string name =
formatter() << get_name() <<
'[' << key <<
'=' << case_cfg[
"value"] <<
']';
436 conditions_.back().set_name(name);
443 default_cfg.
add_child(
"and")[
"glob_on_" + key] =
"*";
445 conditions_.emplace_back(switch_cfg.
mandatory_child(
"else"), default_cfg);
446 const std::string name =
formatter() << get_name() <<
"[else]";
447 conditions_.back().set_name(name);
451 void wml_tag::add_filter(
const config& cond_cfg)
453 config filter = cond_cfg, else_filter;
457 else_filter.add_child(
"not", filter);
460 const std::string name =
formatter() << get_name() <<
"[then]";
461 conditions_.back().set_name(name);
464 for(
auto elseif_cfg : cond_cfg.
child_range(
"elseif")) {
465 config elseif_filter = elseif_cfg, old_else_filter = else_filter;
467 else_filter.add_child(
"not", elseif_filter);
470 conditions_.emplace_back(elseif_cfg.child_or_empty(
"then"), elseif_filter);
471 const std::string name =
formatter() << get_name() <<
"[elseif " <<
i++ <<
"]";
472 conditions_.back().set_name(name);
475 conditions_.emplace_back(cond_cfg.
mandatory_child(
"else"), else_filter);
476 const std::string name =
formatter() << get_name() <<
"[else]";
477 conditions_.back().set_name(name);
481 bool wml_condition::matches(
const config& cfg)
const
496 current = base_tag.
tags_.begin();
497 condition_queue.push(&base_tag);
501 void wml_tag::tag_iterator::ensure_valid_or_end() {
502 while(current == condition_queue.front()->tags_.end()) {
503 condition_queue.pop();
504 if(condition_queue.empty()) {
507 const wml_tag& new_base = *condition_queue.front();
508 current= new_base.
tags_.begin();
509 push_new_tag_conditions(new_base);
516 current = base_tag.
keys_.begin();
517 condition_queue.push(&base_tag);
521 void wml_tag::key_iterator::ensure_valid_or_end() {
522 while(current == condition_queue.front()->keys_.end()) {
523 condition_queue.pop();
524 if(condition_queue.empty()) {
527 const wml_tag& new_base = *condition_queue.front();
528 current = new_base.keys_.begin();
529 push_new_tag_conditions(new_base);
536 current = base_tag.super_refs_.begin();
537 condition_queue.push(&base_tag);
541 void wml_tag::super_iterator::ensure_valid_or_end()
543 while(current == condition_queue.front()->super_refs_.end()) {
544 condition_queue.pop();
545 if(condition_queue.empty()) {
548 const wml_tag& new_base = *condition_queue.front();
549 current = new_base.super_refs_.begin();
550 push_new_tag_conditions(new_base);
554 void wml_tag::push_new_tag_conditions(std::queue<const wml_tag*>& q,
const config& match,
const wml_tag&
tag)
556 for(
const auto& condition :
tag.conditions_) {
557 if(condition.matches(match)) {
A config object defines a single node in a WML file, with access to child nodes.
config & mandatory_child(config_key_type key, int n=0)
Returns the nth child with the given key, or throws an error if there is none.
bool matches(const config &filter) const
void clear_children(T... keys)
bool has_child(config_key_type key) const
Determine whether a config has a child or not.
bool has_attribute(config_key_type key) const
child_itors child_range(config_key_type key)
void append_children(const config &cfg)
Adds children from cfg.
config & add_child(config_key_type key)
wml_key is used to save the information about one key.
Stores information about tag.
void add_link(const std::string &link)
std::string super_
name of tag to extend "super-tag" Extension is smth like inheritance and is used in case when you nee...
const wml_tag * find_tag(const std::string &fullpath, const wml_tag &root, const config &match, bool ignore_super=false) const
Returns pointer to tag using full path to it.
void set_name(const std::string &name)
void add_filter(const config &cond_cfg)
void add_tag(const wml_tag &new_tag)
void print(std::ostream &os)
Prints information about tag to outputstream, recursively is used to print tag info the format is nex...
link_map links_
links to possible children.
int min_
minimum number of occurrences.
void add_switch(const config &switch_cfg)
condition_list conditions_
conditional partial matches
std::vector< wml_condition > condition_list
const wml_key * find_key(const std::string &name, const config &match, bool ignore_super=false) const
Returns pointer to child key.
tag_map tags_
children tags
void add_key(const wml_key &new_key)
int max_
maximum number of occurrences.
void printl(std::ostream &os, int level, int step=4)
the same as wml_tag::print(std::ostream&) but indents different levels with step space.
int max_children_
maximum number of children.
static std::string _(const char *str)
std::string tag(const std::string &tag_name, Args &&... contents)
wml_tag any_tag("", 0, -1, "", true)
struct utils::detail::formula_initer init
@ STRIP_SPACES
REMOVE_EMPTY: remove empty elements.
bool wildcard_string_match(const std::string &str, const std::string &match)
Match using '*' as any number of characters (including none), '+' as one or more characters,...
std::vector< std::string > split(const config_attribute_value &val)
auto * find(Container &container, const Value &value)
Convenience wrapper for using find on a container without needing to comare to end()
This file contains object "tag", which is used to store information about tags while annotation parsi...
static map_location::direction sw
static map_location::direction s