The Battle for Wesnoth  1.17.0-dev
schema_validator.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2011 - 2018 by Sytyi Nick <nsytyi@gmail.com>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #pragma once
16 
17 #include "config_cache.hpp"
18 #include "serialization/parser.hpp"
23 
24 #include <iostream>
25 #include <queue>
26 #include <stack>
27 #include <string>
28 
29 class config;
30 
31 /** @file
32  * One of the realizations of serialization/validator.hpp abstract validator.
33  */
34 namespace schema_validation
35 {
36 /**
37  * Realization of serialization/validator.hpp abstract validator.
38  * Based on stack. Uses some stacks to store different info.
39  */
41 {
42 public:
43  virtual ~schema_validator();
44 
45  /**
46  * Initializes validator from file.
47  * Throws abstract_validator::error if any error.
48  */
49  schema_validator(const std::string& filename, bool validate_schema = false);
50 
51  void set_create_exceptions(bool value)
52  {
53  create_exceptions_ = value;
54  }
55 
56  virtual void open_tag(const std::string& name, const config& parent, int start_line = 0, const std::string& file = "", bool addition = false) override;
57  virtual void close_tag() override;
58  virtual void validate(const config& cfg, const std::string& name, int start_line, const std::string& file) override;
59  virtual void validate_key(const config& cfg, const std::string& name, const config_attribute_value& value, int start_line, const std::string& file) override;
60 
61 private:
62  // types section
63  // Just some magic to ensure zero initialization.
64  struct counter
65  {
66  int cnt;
68  : cnt(0)
69  {
70  }
71  };
72 
73  /** Counters are mapped by tag name. */
74  typedef std::map<std::string, counter> cnt_map;
75 
76  /** And counter maps are organize in stack. */
77  typedef std::stack<cnt_map> cnt_stack;
78 
79 protected:
80  using message_type = int;
82 
83  /**
84  * Messages are cached.
85  * The reason is next: in file where [tag]...[/tag][+tag]...[/tag]
86  * config object will be validated each [/tag]. So message can be as wrong
87  * (when [+tag] section contains missed elements) as duplicated.
88  *
89  * Messages are mapped by config*. That ensures uniqueness.
90  * Also message-maps are organized in stack to avoid memory leaks.
91  */
92  struct message_info
93  {
95  std::string file;
96  int line;
97  int n;
98  std::string tag;
99  std::string key;
100  std::string value;
101  std::string expected;
102 
103  message_info(message_type t, const std::string& file, int line = 0, int n = 0, const std::string& tag = "", const std::string& key = "", const std::string& value = "", const std::string& expected = "")
104  : type(t)
105  , file(file)
106  , line(line)
107  , n(n)
108  , tag(tag)
109  , key(key)
110  , value(value)
111  , expected(expected)
112  {
113  }
114  };
115 
116  /** Controls the way to print errors. */
118 
119  virtual void print(message_info&);
120 private:
121 
122  typedef std::deque<message_info> message_list;
123  typedef std::map<const config*, message_list> message_map;
124 
125  /** Reads config from input. */
126  bool read_config_file(const std::string& filename);
127 
128  /** Shows, if validator is initialized with schema file. */
130 
131  /** Root of schema information. */
133 
134  std::stack<const wml_tag*> stack_;
135 
136  /** Contains number of children. */
137  cnt_stack counter_;
138 
139  /** Caches error messages. */
140  std::stack<message_map> cache_;
141 
142  /** Type validators. */
144 
146 
147 protected:
148  template<typename... T>
149  void queue_message(const config& cfg, T&&... args)
150  {
151  cache_.top()[&cfg].emplace_back(std::forward<T>(args)...);
152  }
153 
154  const wml_tag& active_tag() const;
155  std::string active_tag_path() const;
156  bool have_active_tag() const;
157  bool is_valid() const {return config_read_;}
158  wml_type::ptr find_type(const std::string& type) const;
159 };
160 
161 // A validator specifically designed for validating a schema
162 // In addition to the usual, it verifies that references within the schema are valid, for example via the [link] tag
164 {
165 public:
167  virtual void open_tag(const std::string& name, const config& parent, int start_line = 0, const std::string& file = "", bool addition = false) override;
168  virtual void close_tag() override;
169  virtual void validate(const config& cfg, const std::string& name, int start_line, const std::string& file) override;
170  virtual void validate_key(const config& cfg, const std::string& name, const config_attribute_value& value, int start_line, const std::string& file) override;
171 private:
172  struct reference {
173  reference(const std::string& value, const std::string& file, int line, const std::string& tag)
174  : value_(value)
175  , file_(file)
176  , tag_(tag)
177  , line_(line)
178  {}
179  std::string value_, file_, tag_;
180  int line_;
181  bool match(const std::set<std::string>& with);
182  bool can_find(const wml_tag& root, const config& cfg);
183  bool operator<(const reference& other) const;
184  };
185  std::string current_path() const;
186  std::set<std::string> defined_types_, defined_tag_paths_;
187  std::vector<reference> referenced_types_, referenced_tag_paths_;
188  std::stack<std::string> tag_stack_;
189  std::map<std::string, std::string> links_;
190  std::multimap<std::string, std::string> derivations_;
191  int type_nesting_, condition_nesting_;
192  bool tag_path_exists(const config& cfg, const reference& ref);
193  void check_for_duplicates(const std::string& name, std::vector<std::string>& seen, const config& cfg, message_type type, const std::string& file, int line, const std::string& tag);
194  static bool name_matches(const std::string& pattern, const std::string& name);
195 
196  void print(message_info& message) override;
197  enum { WRONG_TYPE = NEXT_ERROR, WRONG_PATH, DUPLICATE_TAG, DUPLICATE_KEY, NEXT_ERROR };
198 };
199 
200 } // namespace schema_validation{
std::stack< cnt_map > cnt_stack
And counter maps are organize in stack.
std::stack< const wml_tag * > stack_
bool create_exceptions_
Controls the way to print errors.
cnt_stack counter_
Contains number of children.
This file contains object "type", which is used to store information about types while annotation par...
std::multimap< std::string, std::string > derivations_
Variant for storing WML attributes.
Stores information about tag.
Definition: tag.hpp:46
std::deque< message_info > message_list
This file contains information about validation abstract level interface.
std::map< const config *, message_list > message_map
wml_tag root_
Root of schema information.
std::map< std::string, ptr > map
Definition: type.hpp:42
bool config_read_
Shows, if validator is initialized with schema file.
This file contains object "tag", which is used to store information about tags while annotation parsi...
Used in parsing config file.
Definition: validator.hpp:35
std::stack< message_map > cache_
Caches error messages.
virtual void validate_key(const config &cfg, const std::string &name, const config_attribute_value &value, int start_line, const std::string &file) override
Checks if key is allowed and if its value is valid What exactly is validated depends on validator rea...
wml_type::map types_
Type validators.
message_info(message_type t, const std::string &file, int line=0, int n=0, const std::string &tag="", const std::string &key="", const std::string &value="", const std::string &expected="")
schema_validator(const std::string &filename, bool validate_schema=false)
Initializes validator from file.
bool read_config_file(const std::string &filename)
Reads config from input.
static bool operator<(const placing_info &a, const placing_info &b)
Definition: game_state.cpp:139
virtual void close_tag() override
As far as parser is built on stack, some realizations can store stack too.
std::shared_ptr< wml_type > ptr
Definition: type.hpp:41
void queue_message(const config &cfg, T &&... args)
This file contains object "key", which is used to store information about keys while annotation parsi...
double t
Definition: astarsearch.cpp:64
virtual void open_tag(const std::string &name, const config &parent, int start_line=0, const std::string &file="", bool addition=false) override
Is called when parser opens tag.
static const char * match(MatchState *ms, const char *s, const char *p)
Definition: lstrlib.cpp:567
Realization of serialization/validator.hpp abstract validator.
wml_type::ptr find_type(const std::string &type) const
std::map< std::string, counter > cnt_map
Counters are mapped by tag name.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:59
reference(const std::string &value, const std::string &file, int line, const std::string &tag)
virtual void print(message_info &)
virtual void validate(const config &cfg, const std::string &name, int start_line, const std::string &file) override
Validates config.
std::map< std::string, std::string > links_