The Battle for Wesnoth  1.19.0-dev
tag.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2011 - 2024
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 <functional>
25 #include <map>
26 #include <string>
27 #include <vector>
28 #include <queue>
29 
30 #include <boost/iterator/iterator_facade.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::map<std::string, const 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, Map>, 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  std::reference_wrapper<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;
111 public:
112 
114  : name_("")
115  , min_(0)
116  , max_(0)
117  , min_children_(0)
118  , max_children_(INT_MAX)
119  , super_("")
120  , tags_()
121  , keys_()
122  , links_()
123  , fuzzy_(false)
124  , any_tag_(false)
125  {
126  }
127 
128  wml_tag(const std::string& name, int min, int max, const std::string& super = "", bool any = false)
129  : name_(name)
130  , min_(min)
131  , max_(max)
132  , min_children_(0)
133  , max_children_(INT_MAX)
134  , super_(super)
135  , tags_()
136  , keys_()
137  , links_()
138  , fuzzy_(name.find_first_of("*?") != std::string::npos)
139  , any_tag_(any)
140  {
141  }
142 
143  wml_tag(const config&);
144 
146  {
147  }
148 
149  /** Prints information about tag to outputstream, recursively
150  * is used to print tag info
151  * the format is next
152  * [tag]
153  * subtags
154  * keys
155  * name="name"
156  * min="min"
157  * max="max"
158  * [/tag]
159  */
160  void print(std::ostream& os);
161 
162  const std::string& get_name() const
163  {
164  return name_;
165  }
166 
167  int get_min() const
168  {
169  return min_;
170  }
171 
172  int get_max() const
173  {
174  return max_;
175  }
176 
177  int get_min_children() const
178  {
179  return min_children_;
180  }
181 
182  int get_max_children() const
183  {
184  return max_children_;
185  }
186 
187  const std::string& get_super() const
188  {
189  return super_;
190  }
191 
192  bool is_extension() const
193  {
194  return !super_.empty();
195  }
196 
197  bool is_fuzzy() const {
198  return fuzzy_;
199  }
200 
201  bool accepts_any_tag() const {
202  return any_tag_;
203  }
204 
205  void set_name(const std::string& name)
206  {
207  name_ = name;
208  }
209 
210  void set_min(int o)
211  {
212  min_ = o;
213  }
214 
215  void set_max(int o)
216  {
217  max_ = o;
218  }
219 
220  void set_min_children(int o)
221  {
222  min_children_ = o;
223  }
224 
225  void set_max_children(int o)
226  {
227  max_children_ = o;
228  }
229 
230  void set_min(const std::string& s);
231  void set_max(const std::string& s);
232 
233  void set_min_children(const std::string& s);
234  void set_max_children(const std::string& s);
235 
236  void set_super(const std::string& s)
237  {
238  super_ = s;
239  }
240 
241  void set_fuzzy(bool f) {
242  fuzzy_ = f;
243  }
244 
245  void set_any_tag(bool any) {
246  any_tag_ = any;
247  }
248 
249  void add_key(const wml_key& new_key)
250  {
251  keys_.emplace(new_key.get_name(), new_key);
252  }
253 
254  void add_tag(const wml_tag& new_tag)
255  {
256  tags_.emplace(new_tag.name_, new_tag);
257  }
258 
259  void add_link(const std::string& link);
260 
261  void add_switch(const config& switch_cfg);
262 
263  void add_filter(const config& cond_cfg);
264 
265  /**
266  * Tags are usually organized in tree.
267  * This function helps to add a tag to his exact place in tree
268  * @param path - path in subtree to exact place of tag
269  * @param tag - tag to add
270  * @param root - root of schema tree - use to support of adding to link.
271  * Path is getting shotter and shoter with each call.
272  * Path should look like tag1/tag2/parent/ Slash at end is mandatory.
273  */
274  void add_tag(const std::string& path, const wml_tag& tag, wml_tag& root);
275 
276  bool operator<(const wml_tag& t) const
277  {
278  return name_ < t.name_;
279  }
280 
281  bool operator==(const wml_tag& other) const
282  {
283  return name_ == other.name_;
284  }
285 
286  /** Returns pointer to child key. */
287  const wml_key* find_key(const std::string& name, const config& match, bool ignore_super = false) const;
288 
289  /** Returns pointer to child link. */
290  const std::string* find_link(const std::string& name) const;
291 
292  /**
293  * Returns pointer to tag using full path to it.
294  * Also work with links
295  */
296  const wml_tag* find_tag(const std::string& fullpath, const wml_tag& root, const config& match, bool ignore_super = false) const;
297 
298  /** Calls the expansion on each child. */
299  void expand_all(wml_tag& root);
300 
301  boost::iterator_range<tag_iterator> tags(const config& cfg_match) const
302  {
303  return {tag_iterator(*this, cfg_match), tag_iterator()};
304  }
305 
306  boost::iterator_range<key_iterator> keys(const config& cfg_match) const
307  {
308  return {key_iterator(*this, cfg_match), key_iterator()};
309  }
310 
311  boost::iterator_range<super_iterator> super(const config& cfg_match) const {
312  return {super_iterator(*this, cfg_match), super_iterator()};
313  }
314 
315  const link_map& links() const
316  {
317  return links_;
318  }
319 
320  const condition_list& conditions() const
321  {
322  return conditions_;
323  }
324 
325  void remove_key_by_name(const std::string& name)
326  {
327  keys_.erase(name);
328  }
329 
330  /** Removes all keys with this type. Works recursively */
331  void remove_keys_by_type(const std::string& type);
332 
333 private:
334  /** name of tag. */
335  std::string name_;
336 
337  /** minimum number of occurrences. */
338  int min_;
339 
340  /** maximum number of occurrences. */
341  int max_;
342 
343  /** minimum number of children. */
345 
346  /** maximum number of children. */
348 
349  /**
350  * name of tag to extend "super-tag"
351  * Extension is smth like inheritance and is used in case
352  * when you need to use another tag with all his
353  * keys, children, etc. But you also want to allow extra subtags of that tags,
354  * so just linking that tag wouldn't help at all.
355  */
356  std::string super_;
357 
358  /** children tags*/
360 
361  /** keys*/
363 
364  /** links to possible children. */
366 
367  /** conditional partial matches */
369 
370  /** super-tag references */
372 
373  /** whether this is a "fuzzy" tag. */
374  bool fuzzy_;
375 
376  /** whether this tag allows arbitrary subtags. */
377  bool any_tag_;
378 
379  /**
380  * the same as wml_tag::print(std::ostream&)
381  * but indents different levels with step space.
382  * @param os stream to print
383  * @param level current level of indentation
384  * @param step step to next indent
385  */
386  void printl(std::ostream& os, int level, int step = 4);
387 
388  wml_tag* find_tag(const std::string & fullpath, wml_tag & root, const config& match)
389  {
390  return const_cast<wml_tag*>(const_cast<const wml_tag*>(this)->find_tag(fullpath, root, match));
391  }
392 
393  void add_tags(const tag_map& list)
394  {
395  tags_.insert(list.begin(), list.end());
396  }
397 
398  void add_keys(const key_map& list)
399  {
400  keys_.insert(list.begin(), list.end());
401  }
402 
403  void add_links(const link_map& list)
404  {
405  links_.insert(list.begin(), list.end());
406  }
407 
408  void add_conditions(const condition_list& list);
409 
410  /** Expands all "super", storing direct references for easier access. */
411  void expand(wml_tag& root);
412 
413  /** Finds a key with super bookkeeping to handle super cycles. */
414  const wml_key* find_key(const std::string& name, const config& match, bool ignore_super, std::vector<const wml_tag*>& visited) const;
415 
416  /** Finds a tag with super bookkeeping to handle super cycles. */
417  const 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;
418 };
419 
420 /**
421  * Stores information about a conditional portion of a tag.
422  * Format is the same as wml_tag.
423  */
424 class wml_condition : public wml_tag {
426 public:
427  wml_condition(const config& info, const config& filter) : wml_tag(info), filter_(filter) {}
428  bool matches(const config& cfg) const;
429 };
430 }
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:159
Stores information about a conditional portion of a tag.
Definition: tag.hpp:424
wml_condition(const config &info, const config &filter)
Definition: tag.hpp:427
bool matches(const config &cfg) const
Definition: tag.cpp:471
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
std::reference_wrapper< const config > match
Definition: tag.hpp:62
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
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
void init(const wml_tag &base_tag)
Definition: tag.cpp:484
Stores information about tag.
Definition: tag.hpp:48
void add_link(const std::string &link)
Definition: tag.cpp:101
boost::iterator_range< super_iterator > super(const config &cfg_match) const
Definition: tag.hpp:311
int get_min_children() const
Definition: tag.hpp:177
int get_min() const
Definition: tag.hpp:167
const link_map & links() const
Definition: tag.hpp:315
void expand(wml_tag &root)
Expands all "super", storing direct references for easier access.
Definition: tag.cpp:384
void set_super(const std::string &s)
Definition: tag.hpp:236
const std::string & get_name() const
Definition: tag.hpp:162
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:356
bool operator<(const wml_tag &t) const
Definition: tag.hpp:276
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:179
wml_tag(const std::string &name, int min, int max, const std::string &super="", bool any=false)
Definition: tag.hpp:128
const condition_list & conditions() const
Definition: tag.hpp:320
iterator< const wml_tag * > super_iterator
Definition: tag.hpp:110
void set_max(int o)
Definition: tag.hpp:215
std::map< std::string, const wml_tag * > super_list
Definition: tag.hpp:54
std::map< std::string, std::string > link_map
Definition: tag.hpp:52
void remove_key_by_name(const std::string &name)
Definition: tag.hpp:325
void add_tags(const tag_map &list)
Definition: tag.hpp:393
int get_max_children() const
Definition: tag.hpp:182
bool operator==(const wml_tag &other) const
Definition: tag.hpp:281
void set_name(const std::string &name)
Definition: tag.hpp:205
void add_filter(const config &cond_cfg)
Definition: tag.cpp:441
int min_children_
minimum number of children.
Definition: tag.hpp:344
super_list super_refs_
super-tag references
Definition: tag.hpp:371
void set_fuzzy(bool f)
Definition: tag.hpp:241
void add_keys(const key_map &list)
Definition: tag.hpp:398
void add_tag(const wml_tag &new_tag)
Definition: tag.hpp:254
const std::string * find_link(const std::string &name) const
Returns pointer to child link.
Definition: tag.cpp:169
void set_min(int o)
Definition: tag.hpp:210
void set_any_tag(bool any)
Definition: tag.hpp:245
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:365
iterator< wml_tag > tag_iterator
Definition: tag.hpp:108
std::string name_
name of tag.
Definition: tag.hpp:335
void add_conditions(const condition_list &list)
Definition: tag.cpp:379
boost::iterator_range< key_iterator > keys(const config &cfg_match) const
Definition: tag.hpp:306
boost::iterator_range< tag_iterator > tags(const config &cfg_match) const
Definition: tag.hpp:301
bool fuzzy_
whether this is a "fuzzy" tag.
Definition: tag.hpp:374
void remove_keys_by_type(const std::string &type)
Removes all keys with this type.
Definition: tag.cpp:284
iterator< wml_key > key_iterator
Definition: tag.hpp:109
void add_links(const link_map &list)
Definition: tag.hpp:403
int min_
minimum number of occurrences.
Definition: tag.hpp:338
std::map< std::string, wml_tag > tag_map
Definition: tag.hpp:50
bool accepts_any_tag() const
Definition: tag.hpp:201
bool any_tag_
whether this tag allows arbitrary subtags.
Definition: tag.hpp:377
int get_max() const
Definition: tag.hpp:172
bool is_fuzzy() const
Definition: tag.hpp:197
void add_switch(const config &switch_cfg)
Definition: tag.cpp:396
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:544
bool is_extension() const
Definition: tag.hpp:192
condition_list conditions_
conditional partial matches
Definition: tag.hpp:368
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:220
void expand_all(wml_tag &root)
Calls the expansion on each child.
Definition: tag.cpp:272
const std::string & get_super() const
Definition: tag.hpp:187
tag_map tags_
children tags
Definition: tag.hpp:359
wml_tag * find_tag(const std::string &fullpath, wml_tag &root, const config &match)
Definition: tag.hpp:388
void add_key(const wml_key &new_key)
Definition: tag.hpp:249
int max_
maximum number of occurrences.
Definition: tag.hpp:341
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:300
int max_children_
maximum number of children.
Definition: tag.hpp:347
void set_max_children(int o)
Definition: tag.hpp:225
std::string path
Definition: filesystem.cpp:83
logger & info()
Definition: log.cpp:317
This file contains object "key", which is used to store information about keys while annotation parsi...
static map_location::DIRECTION s
#define f