The Battle for Wesnoth  1.17.17+dev
tag.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2011 - 2023
3  by Sytyi Nick <nsytyi@gmail.com>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 /**
17  * @file
18  * This file contains object "tag", which is used to store
19  * information about tags while annotation parsing.
20  */
21 
22 #pragma once
23 
24 #include <map>
25 #include <string>
26 #include <vector>
27 #include <queue>
28 
29 #include <boost/iterator/iterator_facade.hpp>
30 #include <boost/range/iterator.hpp>
31 #include "config.hpp"
33 
34 namespace schema_validation
35 {
36 
37 class wml_condition;
38 
39 /**
40  * Stores information about tag.
41  * Each tags is an element of great tag tree. This tree is close to filesystem:
42  * you can use links and special include directory global/
43  * Normally root is not mentioned in path.
44  * Each tag has name, minimum and maximum occasions number,
45  * and lists of subtags, keys and links.
46  */
47 class wml_tag
48 {
49 public:
50  using tag_map = std::map<std::string, wml_tag>;
51  using key_map = std::map<std::string, wml_key>;
52  using link_map = std::map<std::string, std::string>;
53  using condition_list = std::vector<wml_condition>;
54  using super_list = std::vector<wml_tag*>;
55 private:
56  static void push_new_tag_conditions(std::queue<const wml_tag*>& q, const config& match, const wml_tag& tag);
57  template<typename T, typename Map = std::map<std::string, T>>
58  class iterator : public boost::iterator_facade<iterator<T>, const typename Map::value_type, std::forward_iterator_tag>
59  {
60  std::queue<const wml_tag*> condition_queue;
61  typename Map::const_iterator current;
62  const config& match;
63  public:
64  // Construct a begin iterator
65  iterator(const wml_tag& base_tag, const config& match) : match(match)
66  {
67  init(base_tag);
68  push_new_tag_conditions(base_tag);
70  }
71  // Construct an end iterator
72  iterator() : match(config().child_or_empty("fsdfsdf")) {}
73  private:
75  void init(const wml_tag& base_tag);
76  void ensure_valid_or_end();
77  void increment()
78  {
79  ++current;
81  }
83  {
85  }
86  bool equal(const iterator<T, Map>& other) const
87  {
88  if(condition_queue.empty() && other.condition_queue.empty()) {
89  return true;
90  }
91  if(condition_queue.empty() || other.condition_queue.empty()) {
92  return false;
93  }
94  if(condition_queue.front() != other.condition_queue.front()) {
95  return false;
96  }
97  if(current != other.current) {
98  return false;
99  }
100  return true;
101  }
103  {
104  return *current;
105  }
106  };
107  template<typename T, typename Map> friend class iterator;
110 public:
111 
113  : name_("")
114  , min_(0)
115  , max_(0)
116  , min_children_(0)
117  , max_children_(INT_MAX)
118  , super_("")
119  , tags_()
120  , keys_()
121  , links_()
122  , fuzzy_(false)
123  , any_tag_(false)
124  {
125  }
126 
127  wml_tag(const std::string& name, int min, int max, const std::string& super = "", bool any = false)
128  : name_(name)
129  , min_(min)
130  , max_(max)
131  , min_children_(0)
132  , max_children_(INT_MAX)
133  , super_(super)
134  , tags_()
135  , keys_()
136  , links_()
137  , fuzzy_(name.find_first_of("*?") != std::string::npos)
138  , any_tag_(any)
139  {
140  }
141 
142  wml_tag(const config&);
143 
145  {
146  }
147 
148  /** Prints information about tag to outputstream, recursively
149  * is used to print tag info
150  * the format is next
151  * [tag]
152  * subtags
153  * keys
154  * name="name"
155  * min="min"
156  * max="max"
157  * [/tag]
158  */
159  void print(std::ostream& os);
160 
161  const std::string& get_name() const
162  {
163  return name_;
164  }
165 
166  int get_min() const
167  {
168  return min_;
169  }
170 
171  int get_max() const
172  {
173  return max_;
174  }
175 
176  int get_min_children() const
177  {
178  return min_children_;
179  }
180 
181  int get_max_children() const
182  {
183  return max_children_;
184  }
185 
186  const std::string& get_super() const
187  {
188  return super_;
189  }
190 
191  bool is_extension() const
192  {
193  return !super_.empty();
194  }
195 
196  bool is_fuzzy() const {
197  return fuzzy_;
198  }
199 
200  bool accepts_any_tag() const {
201  return any_tag_;
202  }
203 
204  void set_name(const std::string& name)
205  {
206  name_ = name;
207  }
208 
209  void set_min(int o)
210  {
211  min_ = o;
212  }
213 
214  void set_max(int o)
215  {
216  max_ = o;
217  }
218 
219  void set_min_children(int o)
220  {
221  min_children_ = o;
222  }
223 
224  void set_max_children(int o)
225  {
226  max_children_ = o;
227  }
228 
229  void set_min(const std::string& s);
230  void set_max(const std::string& s);
231 
232  void set_min_children(const std::string& s);
233  void set_max_children(const std::string& s);
234 
235  void set_super(const std::string& s)
236  {
237  super_ = s;
238  }
239 
240  void set_fuzzy(bool f) {
241  fuzzy_ = f;
242  }
243 
244  void set_any_tag(bool any) {
245  any_tag_ = any;
246  }
247 
248  void add_key(const wml_key& new_key)
249  {
250  keys_.emplace(new_key.get_name(), new_key);
251  }
252 
253  void add_tag(const wml_tag& new_tag)
254  {
255  tags_.emplace(new_tag.name_, new_tag);
256  }
257 
258  void add_link(const std::string& link);
259 
260  void add_switch(const config& switch_cfg);
261 
262  void add_filter(const config& cond_cfg);
263 
264  /**
265  * Tags are usually organized in tree.
266  * This function helps to add a tag to his exact place in tree
267  * @param path - path in subtree to exact place of tag
268  * @param tag - tag to add
269  * @param root - root of schema tree - use to support of adding to link.
270  * Path is getting shotter and shoter with each call.
271  * Path should look like tag1/tag2/parent/ Slash at end is mandatory.
272  */
273  void add_tag(const std::string& path, const wml_tag& tag, wml_tag& root);
274 
275  bool operator<(const wml_tag& t) const
276  {
277  return name_ < t.name_;
278  }
279 
280  bool operator==(const wml_tag& other) const
281  {
282  return name_ == other.name_;
283  }
284 
285  /** Returns pointer to child key. */
286  const wml_key* find_key(const std::string& name, const config& match, bool ignore_super = false) const;
287 
288  /** Returns pointer to child link. */
289  const std::string* find_link(const std::string& name) const;
290 
291  /**
292  * Returns pointer to tag using full path to it.
293  * Also work with links
294  */
295  const wml_tag* find_tag(const std::string& fullpath, const wml_tag& root, const config& match, bool ignore_super = false) const;
296 
297  /** Calls the expansion on each child. */
298  void expand_all(wml_tag& root);
299 
300  boost::iterator_range<tag_iterator> tags(const config& cfg_match) const
301  {
302  return {tag_iterator(*this, cfg_match), tag_iterator()};
303  }
304 
305  boost::iterator_range<key_iterator> keys(const config& cfg_match) const
306  {
307  return {key_iterator(*this, cfg_match), key_iterator()};
308  }
309 
310  const link_map& links() const
311  {
312  return links_;
313  }
314 
315  const condition_list& conditions() const
316  {
317  return conditions_;
318  }
319 
320  void remove_key_by_name(const std::string& name)
321  {
322  keys_.erase(name);
323  }
324 
325  /** Removes all keys with this type. Works recursively */
326  void remove_keys_by_type(const std::string& type);
327 
328 private:
329  /** name of tag. */
330  std::string name_;
331 
332  /** minimum number of occurrences. */
333  int min_;
334 
335  /** maximum number of occurrences. */
336  int max_;
337 
338  /** minimum number of children. */
340 
341  /** maximum number of children. */
343 
344  /**
345  * name of tag to extend "super-tag"
346  * Extension is smth like inheritance and is used in case
347  * when you need to use another tag with all his
348  * keys, children, etc. But you also want to allow extra subtags of that tags,
349  * so just linking that tag wouldn't help at all.
350  */
351  std::string super_;
352 
353  /** children tags*/
355 
356  /** keys*/
358 
359  /** links to possible children. */
361 
362  /** conditional partial matches */
364 
365  /** super-tag references */
367 
368  /** whether this is a "fuzzy" tag. */
369  bool fuzzy_;
370 
371  /** whether this tag allows arbitrary subtags. */
372  bool any_tag_;
373 
374  /**
375  * the same as wml_tag::print(std::ostream&)
376  * but indents different levels with step space.
377  * @param os stream to print
378  * @param level current level of indentation
379  * @param step step to next indent
380  */
381  void printl(std::ostream& os, int level, int step = 4);
382 
383  wml_tag* find_tag(const std::string & fullpath, wml_tag & root, const config& match)
384  {
385  return const_cast<wml_tag*>(const_cast<const wml_tag*>(this)->find_tag(fullpath, root, match));
386  }
387 
388  void add_tags(const tag_map& list)
389  {
390  tags_.insert(list.begin(), list.end());
391  }
392 
393  void add_keys(const key_map& list)
394  {
395  keys_.insert(list.begin(), list.end());
396  }
397 
398  void add_links(const link_map& list)
399  {
400  links_.insert(list.begin(), list.end());
401  }
402 
403  void add_conditions(const condition_list& list);
404 
405  /** Expands all "super", storing direct references for easier access. */
406  void expand(wml_tag& root);
407 };
408 
409 /**
410  * Stores information about a conditional portion of a tag.
411  * Format is the same as wml_tag.
412  */
413 class wml_condition : public wml_tag {
415 public:
416  wml_condition(const config& info, const config& filter) : wml_tag(info), filter_(filter) {}
417  bool matches(const config& cfg) const;
418 };
419 }
double t
Definition: astarsearch.cpp:65
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:161
Stores information about a conditional portion of a tag.
Definition: tag.hpp:413
wml_condition(const config &info, const config &filter)
Definition: tag.hpp:416
bool matches(const config &cfg) const
Definition: tag.cpp:446
wml_key is used to save the information about one key.
Definition: key.hpp:37
const std::string & get_name() const
Definition: key.hpp:59
iterator< T, Map >::reference dereference() const
Definition: tag.hpp:102
bool equal(const iterator< T, Map > &other) const
Definition: tag.hpp:86
iterator(const wml_tag &base_tag, const config &match)
Definition: tag.hpp:65
void push_new_tag_conditions(const wml_tag &tag)
Definition: tag.hpp:82
void init(const wml_tag &base_tag)
Definition: tag.cpp:459
friend class boost::iterator_core_access
Definition: tag.hpp:74
std::queue< const wml_tag * > condition_queue
Definition: tag.hpp:60
Map::const_iterator current
Definition: tag.hpp:61
Stores information about tag.
Definition: tag.hpp:48
void add_link(const std::string &link)
Definition: tag.cpp:101
int get_min_children() const
Definition: tag.hpp:176
int get_min() const
Definition: tag.hpp:166
const link_map & links() const
Definition: tag.hpp:310
void expand(wml_tag &root)
Expands all "super", storing direct references for easier access.
Definition: tag.cpp:355
void set_super(const std::string &s)
Definition: tag.hpp:235
const std::string & get_name() const
Definition: tag.hpp:161
std::string super_
name of tag to extend "super-tag" Extension is smth like inheritance and is used in case when you nee...
Definition: tag.hpp:351
bool operator<(const wml_tag &t) const
Definition: tag.hpp:275
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.
Definition: tag.cpp:165
wml_tag(const std::string &name, int min, int max, const std::string &super="", bool any=false)
Definition: tag.hpp:127
const condition_list & conditions() const
Definition: tag.hpp:315
void set_max(int o)
Definition: tag.hpp:214
std::map< std::string, std::string > link_map
Definition: tag.hpp:52
void remove_key_by_name(const std::string &name)
Definition: tag.hpp:320
void add_tags(const tag_map &list)
Definition: tag.hpp:388
int get_max_children() const
Definition: tag.hpp:181
bool operator==(const wml_tag &other) const
Definition: tag.hpp:280
void set_name(const std::string &name)
Definition: tag.hpp:204
void add_filter(const config &cond_cfg)
Definition: tag.cpp:416
int min_children_
minimum number of children.
Definition: tag.hpp:339
super_list super_refs_
super-tag references
Definition: tag.hpp:366
void set_fuzzy(bool f)
Definition: tag.hpp:240
void add_keys(const key_map &list)
Definition: tag.hpp:393
void add_tag(const wml_tag &new_tag)
Definition: tag.hpp:253
std::vector< wml_tag * > super_list
Definition: tag.hpp:54
const std::string * find_link(const std::string &name) const
Returns pointer to child link.
Definition: tag.cpp:155
void set_min(int o)
Definition: tag.hpp:209
void set_any_tag(bool any)
Definition: tag.hpp:244
std::map< std::string, wml_key > key_map
Definition: tag.hpp:51
void set_min_children(const std::string &s)
void print(std::ostream &os)
Prints information about tag to outputstream, recursively is used to print tag info the format is nex...
Definition: tag.cpp:80
link_map links_
links to possible children.
Definition: tag.hpp:360
iterator< wml_tag > tag_iterator
Definition: tag.hpp:108
std::string name_
name of tag.
Definition: tag.hpp:330
void add_conditions(const condition_list &list)
Definition: tag.cpp:350
boost::iterator_range< key_iterator > keys(const config &cfg_match) const
Definition: tag.hpp:305
boost::iterator_range< tag_iterator > tags(const config &cfg_match) const
Definition: tag.hpp:300
bool fuzzy_
whether this is a "fuzzy" tag.
Definition: tag.hpp:369
void remove_keys_by_type(const std::string &type)
Removes all keys with this type.
Definition: tag.cpp:255
iterator< wml_key > key_iterator
Definition: tag.hpp:109
void add_links(const link_map &list)
Definition: tag.hpp:398
int min_
minimum number of occurrences.
Definition: tag.hpp:333
std::map< std::string, wml_tag > tag_map
Definition: tag.hpp:50
bool accepts_any_tag() const
Definition: tag.hpp:200
bool any_tag_
whether this tag allows arbitrary subtags.
Definition: tag.hpp:372
int get_max() const
Definition: tag.hpp:171
bool is_fuzzy() const
Definition: tag.hpp:196
void add_switch(const config &switch_cfg)
Definition: tag.cpp:371
void set_max_children(const std::string &s)
static void push_new_tag_conditions(std::queue< const wml_tag * > &q, const config &match, const wml_tag &tag)
Definition: tag.cpp:498
bool is_extension() const
Definition: tag.hpp:191
condition_list conditions_
conditional partial matches
Definition: tag.hpp:363
std::vector< wml_condition > condition_list
Definition: tag.hpp:53
const wml_key * find_key(const std::string &name, const config &match, bool ignore_super=false) const
Returns pointer to child key.
Definition: tag.cpp:109
void set_min_children(int o)
Definition: tag.hpp:219
void expand_all(wml_tag &root)
Calls the expansion on each child.
Definition: tag.cpp:243
const std::string & get_super() const
Definition: tag.hpp:186
tag_map tags_
children tags
Definition: tag.hpp:354
wml_tag * find_tag(const std::string &fullpath, wml_tag &root, const config &match)
Definition: tag.hpp:383
void add_key(const wml_key &new_key)
Definition: tag.hpp:248
int max_
maximum number of occurrences.
Definition: tag.hpp:336
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.
Definition: tag.cpp:271
int max_children_
maximum number of children.
Definition: tag.hpp:342
void set_max_children(int o)
Definition: tag.hpp:224
std::string path
Definition: filesystem.cpp:83
logger & info()
Definition: log.cpp:232
This file contains object "key", which is used to store information about keys while annotation parsi...
static map_location::DIRECTION s
#define f