Split tag.hpp into three files
This commit is contained in:
parent
df4413ae66
commit
a32e279b7c
10 changed files with 510 additions and 367 deletions
|
@ -2809,7 +2809,21 @@
|
|||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Release|Win32'">$(IntDir)SDL\</ObjectFileName>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\seed_rng.cpp" />
|
||||
<ClCompile Include="..\..\src\serialization\tag.cpp">
|
||||
<ClCompile Include="..\..\src\serialization\schema\key.cpp">
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)Serialization\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|Win32'">$(IntDir)Serialization\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)Serialization\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Debug|Win32'">$(IntDir)Serialization\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Release|Win32'">$(IntDir)Serialization\</ObjectFileName>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\serialization\schema\tag.cpp">
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)Serialization\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|Win32'">$(IntDir)Serialization\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)Serialization\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Debug|Win32'">$(IntDir)Serialization\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Release|Win32'">$(IntDir)Serialization\</ObjectFileName>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\serialization\schema\type.cpp">
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)Serialization\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|Win32'">$(IntDir)Serialization\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)Serialization\</ObjectFileName>
|
||||
|
@ -4033,7 +4047,9 @@
|
|||
<ClInclude Include="..\..\src\theme.hpp" />
|
||||
<ClInclude Include="..\..\src\time_of_day.hpp" />
|
||||
<ClInclude Include="..\..\src\tod_manager.hpp" />
|
||||
<ClInclude Include="..\..\src\serialization\tag.hpp" />
|
||||
<ClInclude Include="..\..\src\serialization\schema\key.hpp" />
|
||||
<ClInclude Include="..\..\src\serialization\schema\tag.hpp" />
|
||||
<ClInclude Include="..\..\src\serialization\schema\type.hpp" />
|
||||
<ClInclude Include="..\..\src\tooltips.hpp" />
|
||||
<ClInclude Include="..\..\src\units\abilities.hpp" />
|
||||
<ClInclude Include="..\..\src\units\animation.hpp" />
|
||||
|
|
|
@ -1010,7 +1010,13 @@
|
|||
<ClCompile Include="..\..\src\utils\name_generator_factory.cpp">
|
||||
<Filter>utils</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\serialization\tag.cpp">
|
||||
<ClCompile Include="..\..\src\serialization\schema\key.cpp">
|
||||
<Filter>serialization</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\serialization\schema\tag.cpp">
|
||||
<Filter>serialization</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\serialization\schema\type.cpp">
|
||||
<Filter>serialization</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\tests\main.cpp">
|
||||
|
@ -2513,7 +2519,13 @@
|
|||
<ClInclude Include="..\..\src\utils\scope_exit.hpp">
|
||||
<Filter>utils</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\serialization\tag.hpp">
|
||||
<ClInclude Include="..\..\src\serialization\schema\key.hpp">
|
||||
<Filter>serialization</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\serialization\schema\tag.hpp">
|
||||
<Filter>serialization</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\serialization\schema\type.hpp">
|
||||
<Filter>serialization</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\actions\advancement.hpp">
|
||||
|
|
|
@ -21,7 +21,9 @@ serialization/parser.cpp
|
|||
serialization/preprocessor.cpp
|
||||
serialization/schema_validator.cpp
|
||||
serialization/string_utils.cpp
|
||||
serialization/tag.cpp
|
||||
serialization/schema/key.cpp
|
||||
serialization/schema/tag.cpp
|
||||
serialization/schema/type.cpp
|
||||
serialization/tokenizer.cpp
|
||||
serialization/unicode.cpp
|
||||
serialization/validator.cpp
|
||||
|
|
63
src/serialization/schema/key.cpp
Normal file
63
src/serialization/schema/key.cpp
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
Copyright (C) 2011 - 2018 by Sytyi Nick <nsytyi@gmail.com>
|
||||
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Implementation of key.hpp.
|
||||
*/
|
||||
|
||||
#include "serialization/schema/key.hpp"
|
||||
|
||||
#include "config.hpp"
|
||||
|
||||
namespace schema_validation
|
||||
{
|
||||
|
||||
class_key::class_key(const config& cfg)
|
||||
: name_(cfg["name"].str())
|
||||
, type_(cfg["type"].str())
|
||||
, default_()
|
||||
, mandatory_(false)
|
||||
, fuzzy_(name_.find_first_of("*?") != std::string::npos)
|
||||
{
|
||||
if(cfg.has_attribute("mandatory")) {
|
||||
mandatory_ = cfg["mandatory"].to_bool();
|
||||
} else {
|
||||
if(cfg.has_attribute("default")) {
|
||||
default_ = cfg["default"].str();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void class_key::print(std::ostream& os, int level) const
|
||||
{
|
||||
std::string s;
|
||||
for(int j = 0; j < level; j++) {
|
||||
s.append(" ");
|
||||
}
|
||||
|
||||
os << s << "[key]\n" << s << " name=\"" << name_ << "\"\n" << s << " type=\"" << type_ << "\"\n";
|
||||
|
||||
if(is_mandatory()) {
|
||||
os << s << " mandatory=\"true\"\n";
|
||||
} else {
|
||||
os << s << " default=" << default_ << "\n";
|
||||
}
|
||||
|
||||
// TODO: Other attributes
|
||||
|
||||
os << s << "[/key]\n";
|
||||
}
|
||||
|
||||
} // namespace schema_validation
|
143
src/serialization/schema/key.hpp
Normal file
143
src/serialization/schema/key.hpp
Normal file
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
Copyright (C) 2011 - 2018 by Sytyi Nick <nsytyi@gmail.com>
|
||||
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file contains object "key", which is used to store
|
||||
* information about keys while annotation parsing.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
class config;
|
||||
|
||||
namespace schema_validation
|
||||
{
|
||||
|
||||
/**
|
||||
* class_key is used to save the information about one key.
|
||||
* Key has next info: name, type, default value or key is mandatory.
|
||||
*/
|
||||
class class_key
|
||||
{
|
||||
public:
|
||||
class_key()
|
||||
: name_("")
|
||||
, type_("")
|
||||
, default_("\"\"")
|
||||
, mandatory_(false)
|
||||
, fuzzy_(false)
|
||||
{
|
||||
}
|
||||
|
||||
class_key(const std::string& name, const std::string& type, const std::string& def = "\"\"")
|
||||
: name_(name)
|
||||
, type_(type)
|
||||
, default_(def)
|
||||
, mandatory_(def.empty())
|
||||
, fuzzy_(name.find_first_of("*?") != std::string::npos)
|
||||
{
|
||||
}
|
||||
|
||||
class_key(const config&);
|
||||
|
||||
const std::string& get_name() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
const std::string& get_type() const
|
||||
{
|
||||
return type_;
|
||||
}
|
||||
|
||||
const std::string& get_default() const
|
||||
{
|
||||
return default_;
|
||||
}
|
||||
|
||||
bool is_mandatory() const
|
||||
{
|
||||
return mandatory_;
|
||||
}
|
||||
|
||||
bool is_fuzzy() const {
|
||||
return fuzzy_;
|
||||
}
|
||||
|
||||
void set_name(const std::string& name)
|
||||
{
|
||||
name_ = name;
|
||||
}
|
||||
|
||||
void set_type(const std::string& type)
|
||||
{
|
||||
type_ = type;
|
||||
}
|
||||
|
||||
void set_default(const std::string& def)
|
||||
{
|
||||
default_ = def;
|
||||
if(def.empty()) {
|
||||
mandatory_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
void set_mandatory(bool mandatory)
|
||||
{
|
||||
mandatory_ = mandatory;
|
||||
}
|
||||
|
||||
void set_fuzzy(bool f)
|
||||
{
|
||||
fuzzy_ = f;
|
||||
}
|
||||
|
||||
/** is used to print key info
|
||||
* the format is next
|
||||
* [key]
|
||||
* name="name"
|
||||
* type="type"
|
||||
* default="default"
|
||||
* mandatory="true/false"
|
||||
* [/key]
|
||||
*/
|
||||
void print(std::ostream& os, int level) const;
|
||||
|
||||
/** Compares keys by name. Used in std::sort, i.e. */
|
||||
bool operator<(const class_key& k) const
|
||||
{
|
||||
return (get_name() < k.get_name());
|
||||
}
|
||||
|
||||
private:
|
||||
/** Name of key. */
|
||||
std::string name_;
|
||||
|
||||
/** Type of key. */
|
||||
std::string type_;
|
||||
|
||||
/** Default value. */
|
||||
std::string default_;
|
||||
|
||||
/** Shows, if key is a mandatory key. */
|
||||
bool mandatory_;
|
||||
|
||||
/** Whether the key is a fuzzy match. */
|
||||
bool fuzzy_;
|
||||
};
|
||||
}
|
|
@ -17,149 +17,15 @@
|
|||
* Implementation of tag.hpp.
|
||||
*/
|
||||
|
||||
#include "serialization/tag.hpp"
|
||||
#include "serialization/schema/tag.hpp"
|
||||
#include "serialization/string_utils.hpp"
|
||||
#include "boost/optional.hpp"
|
||||
#include "formatter.hpp"
|
||||
|
||||
#include "config.hpp"
|
||||
|
||||
namespace schema_validation
|
||||
{
|
||||
|
||||
class_tag any_tag("", 0, -1, "", true);
|
||||
|
||||
/*WIKI
|
||||
* @begin{parent}{name="wml_schema/tag/"}
|
||||
* @begin{tag}{name="key"}{min=0}{max=-1}
|
||||
* @begin{table}{config}
|
||||
* name & string & & The name of key. $
|
||||
* type & string & & The type of key value. $
|
||||
* default & string & & The default value of the key. $
|
||||
* mandatory & string & & Shows if key is mandatory $
|
||||
* @end{table}
|
||||
* @end{tag}{name="key"}
|
||||
* @end{parent}{name="wml_schema/tag/"}
|
||||
*/
|
||||
std::shared_ptr<class_type> class_type::from_config(const config& cfg)
|
||||
{
|
||||
boost::optional<config::const_child_itors> composite_range;
|
||||
std::shared_ptr<class_type> type;
|
||||
if(cfg.has_child("union")) {
|
||||
type = std::make_shared<class_type_union>(cfg["name"]);
|
||||
composite_range.emplace(cfg.child("union").child_range("type"));
|
||||
} else if(cfg.has_child("intersection")) {
|
||||
type = std::make_shared<class_type_intersection>(cfg["name"]);
|
||||
composite_range.emplace(cfg.child("intersection").child_range("type"));
|
||||
} else if(cfg.has_child("list")) {
|
||||
const config& list_cfg = cfg.child("list");
|
||||
int list_min = list_cfg["min"].to_int();
|
||||
int list_max = list_cfg["max"].str() == "infinite" ? -1 : list_cfg["max"].to_int(-1);
|
||||
if(list_max < 0) list_max = INT_MAX;
|
||||
type = std::make_shared<class_type_list>(cfg["name"], list_cfg["split"].str("\\s*,\\s*"), list_min, list_max);
|
||||
composite_range.emplace(list_cfg.child_range("element"));
|
||||
} else if(cfg.has_attribute("value")) {
|
||||
type = std::make_shared<class_type_simple>(cfg["name"], cfg["value"]);
|
||||
} else if(cfg.has_attribute("link")) {
|
||||
type = std::make_shared<class_type_alias>(cfg["name"], cfg["link"]);
|
||||
}
|
||||
if(composite_range) {
|
||||
auto composite_type = std::dynamic_pointer_cast<class_type_composite>(type);
|
||||
for(const config& elem : *composite_range) {
|
||||
composite_type->add_type(class_type::from_config(elem));
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
bool class_type_simple::matches(const std::string& value, const map&) const
|
||||
{
|
||||
boost::smatch sub;
|
||||
return boost::regex_match(value, sub, pattern_);
|
||||
}
|
||||
|
||||
bool class_type_alias::matches(const std::string& value, const map& type_map) const
|
||||
{
|
||||
if(!cached_) {
|
||||
auto it = type_map.find(link_);
|
||||
if(it == type_map.end()) {
|
||||
// TODO: Error message about the invalid type?
|
||||
return false;
|
||||
}
|
||||
cached_ = it->second;
|
||||
}
|
||||
return cached_->matches(value, type_map);
|
||||
}
|
||||
|
||||
bool class_type_union::matches(const std::string& value, const map& type_map) const
|
||||
{
|
||||
for(const auto& type : subtypes_) {
|
||||
if(type->matches(value, type_map)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool class_type_intersection::matches(const std::string& value, const map& type_map) const
|
||||
{
|
||||
for(const auto& type : subtypes_) {
|
||||
if(!type->matches(value, type_map)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool class_type_list::matches(const std::string& value, const map& type_map) const
|
||||
{
|
||||
boost::sregex_token_iterator it(value.begin(), value.end(), split_, -1), end;
|
||||
int n = 0;
|
||||
bool result = std::all_of(it, end, [this, &type_map, &n](const boost::ssub_match& match){
|
||||
// Not sure if this is necessary?
|
||||
if(!match.matched) return true;
|
||||
n++;
|
||||
return this->class_type_union::matches(std::string(match.first, match.second), type_map);
|
||||
});
|
||||
return result && n >= min_ && n <= max_;
|
||||
}
|
||||
|
||||
class_key::class_key(const config& cfg)
|
||||
: name_(cfg["name"].str())
|
||||
, type_(cfg["type"].str())
|
||||
, default_()
|
||||
, mandatory_(false)
|
||||
, fuzzy_(name_.find_first_of("*?") != std::string::npos)
|
||||
{
|
||||
if(cfg.has_attribute("mandatory")) {
|
||||
mandatory_ = cfg["mandatory"].to_bool();
|
||||
} else {
|
||||
if(cfg.has_attribute("default")) {
|
||||
default_ = cfg["default"].str();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void class_key::print(std::ostream& os, int level) const
|
||||
{
|
||||
std::string s;
|
||||
for(int j = 0; j < level; j++) {
|
||||
s.append(" ");
|
||||
}
|
||||
|
||||
os << s << "[key]\n" << s << " name=\"" << name_ << "\"\n" << s << " type=\"" << type_ << "\"\n";
|
||||
|
||||
if(is_mandatory()) {
|
||||
os << s << " mandatory=\"true\"\n";
|
||||
} else {
|
||||
os << s << " default=" << default_ << "\n";
|
||||
}
|
||||
|
||||
// TODO: Other attributes
|
||||
|
||||
os << s << "[/key]\n";
|
||||
}
|
||||
|
||||
class_tag::class_tag(const config& cfg)
|
||||
: name_(cfg["name"].str())
|
||||
, min_(cfg["min"].to_int())
|
||||
|
@ -208,6 +74,22 @@ void class_tag::print(std::ostream& os)
|
|||
printl(os, 4, 4);
|
||||
}
|
||||
|
||||
void class_tag::set_min(const std::string& s)
|
||||
{
|
||||
std::istringstream i(s);
|
||||
if(!(i >> min_)) {
|
||||
min_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void class_tag::set_max(const std::string& s)
|
||||
{
|
||||
std::istringstream i(s);
|
||||
if(!(i >> max_)) {
|
||||
max_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void class_tag::add_link(const std::string& link)
|
||||
{
|
||||
std::string::size_type pos_last = link.rfind('/');
|
||||
|
@ -491,7 +373,7 @@ void class_tag::expand(class_tag& root)
|
|||
super_refs_.push_back(super_tag);
|
||||
} else {
|
||||
// TODO: Detect super cycles too!
|
||||
std::cerr << "the same" << super_tag->name_ << "\n";
|
||||
//std::cerr << "the same" << super_tag->name_ << "\n";
|
||||
}
|
||||
}
|
||||
// TODO: Warn if the super doesn't exist
|
|
@ -14,232 +14,25 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* This file contains objects "tag" and "key", which are used to store
|
||||
* information about tags and keys while annotation parsing.
|
||||
* This file contains object "tag", which is used to store
|
||||
* information about tags while annotation parsing.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/iterator/iterator_facade.hpp>
|
||||
#include <boost/range/iterator.hpp>
|
||||
#include "config.hpp"
|
||||
#include "serialization/schema/key.hpp"
|
||||
|
||||
namespace schema_validation
|
||||
{
|
||||
|
||||
/**
|
||||
* Stores information about a schema type.
|
||||
* This is an abstract base class for several variants of schema type.
|
||||
*/
|
||||
class class_type {
|
||||
protected:
|
||||
std::string name_;
|
||||
public:
|
||||
class_type() = delete;
|
||||
explicit class_type(const std::string& name) : name_(name) {}
|
||||
using ptr = std::shared_ptr<class_type>;
|
||||
using map = std::map<std::string, ptr>;
|
||||
virtual bool matches(const std::string& value, const map& type_map) const = 0;
|
||||
static std::shared_ptr<class_type> from_config(const config& cfg);
|
||||
};
|
||||
|
||||
/**
|
||||
* Stores information about a schema type.
|
||||
* This type represents a simple pattern match.
|
||||
*/
|
||||
class class_type_simple : public class_type {
|
||||
boost::regex pattern_;
|
||||
public:
|
||||
class_type_simple(const std::string& name, const std::string& pattern) : class_type(name), pattern_(pattern) {}
|
||||
bool matches(const std::string& value, const map& type_map) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stores information about a schema type.
|
||||
* This type represents a name alias for another type.
|
||||
*/
|
||||
class class_type_alias : public class_type {
|
||||
mutable std::shared_ptr<class_type> cached_;
|
||||
std::string link_;
|
||||
public:
|
||||
class_type_alias(const std::string& name, const std::string& link) : class_type(name), link_(link) {}
|
||||
bool matches(const std::string& value, const map& type_map) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stores information about a schema type.
|
||||
* This is an abstract base class for composite types.
|
||||
*/
|
||||
class class_type_composite : public class_type {
|
||||
protected:
|
||||
std::vector<std::shared_ptr<class_type>> subtypes_;
|
||||
public:
|
||||
explicit class_type_composite(const std::string& name) : class_type(name) {}
|
||||
void add_type(std::shared_ptr<class_type> type)
|
||||
{
|
||||
subtypes_.push_back(type);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Stores information about a schema type.
|
||||
* Represents a union type, which matches if any of its subtypes match.
|
||||
*/
|
||||
class class_type_union : public class_type_composite {
|
||||
public:
|
||||
explicit class_type_union(const std::string& name) : class_type_composite(name) {}
|
||||
bool matches(const std::string& value, const map& type_map) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stores information about a schema type.
|
||||
* Represents an intersection type, which matches if all of its subtypes match.
|
||||
*/
|
||||
class class_type_intersection : public class_type_composite {
|
||||
public:
|
||||
explicit class_type_intersection(const std::string& name) : class_type_composite(name) {}
|
||||
bool matches(const std::string& value, const map& type_map) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stores information about a schema type.
|
||||
* Represents a list type, where each list element is itself a union.
|
||||
*/
|
||||
class class_type_list : public class_type_union {
|
||||
boost::regex split_;
|
||||
int min_ = 0, max_ = -1;
|
||||
public:
|
||||
class_type_list(const std::string& name, const std::string& pattern, int min, int max)
|
||||
: class_type_union(name)
|
||||
, split_(pattern)
|
||||
, min_(min)
|
||||
, max_(max)
|
||||
{}
|
||||
bool matches(const std::string& value, const map& type_map) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* class_key is used to save the information about one key.
|
||||
* Key has next info: name, type, default value or key is mandatory.
|
||||
*/
|
||||
class class_key
|
||||
{
|
||||
public:
|
||||
class_key()
|
||||
: name_("")
|
||||
, type_("")
|
||||
, default_("\"\"")
|
||||
, mandatory_(false)
|
||||
, fuzzy_(false)
|
||||
{
|
||||
}
|
||||
|
||||
class_key(const std::string& name, const std::string& type, const std::string& def = "\"\"")
|
||||
: name_(name)
|
||||
, type_(type)
|
||||
, default_(def)
|
||||
, mandatory_(def.empty())
|
||||
, fuzzy_(name.find_first_of("*?") != std::string::npos)
|
||||
{
|
||||
}
|
||||
|
||||
class_key(const config&);
|
||||
|
||||
const std::string& get_name() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
const std::string& get_type() const
|
||||
{
|
||||
return type_;
|
||||
}
|
||||
|
||||
const std::string& get_default() const
|
||||
{
|
||||
return default_;
|
||||
}
|
||||
|
||||
bool is_mandatory() const
|
||||
{
|
||||
return mandatory_;
|
||||
}
|
||||
|
||||
bool is_fuzzy() const {
|
||||
return fuzzy_;
|
||||
}
|
||||
|
||||
void set_name(const std::string& name)
|
||||
{
|
||||
name_ = name;
|
||||
}
|
||||
|
||||
void set_type(const std::string& type)
|
||||
{
|
||||
type_ = type;
|
||||
}
|
||||
|
||||
void set_default(const std::string& def)
|
||||
{
|
||||
default_ = def;
|
||||
if(def.empty()) {
|
||||
mandatory_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
void set_mandatory(bool mandatory)
|
||||
{
|
||||
mandatory_ = mandatory;
|
||||
}
|
||||
|
||||
void set_fuzzy(bool f)
|
||||
{
|
||||
fuzzy_ = f;
|
||||
}
|
||||
|
||||
/** is used to print key info
|
||||
* the format is next
|
||||
* [key]
|
||||
* name="name"
|
||||
* type="type"
|
||||
* default="default"
|
||||
* mandatory="true/false"
|
||||
* [/key]
|
||||
*/
|
||||
void print(std::ostream& os, int level) const;
|
||||
|
||||
/** Compares keys by name. Used in std::sort, i.e. */
|
||||
bool operator<(const class_key& k) const
|
||||
{
|
||||
return (get_name() < k.get_name());
|
||||
}
|
||||
|
||||
private:
|
||||
/** Name of key. */
|
||||
std::string name_;
|
||||
|
||||
/** Type of key. */
|
||||
std::string type_;
|
||||
|
||||
/** Default value. */
|
||||
std::string default_;
|
||||
|
||||
/** Shows, if key is a mandatory key. */
|
||||
bool mandatory_;
|
||||
|
||||
/** Whether the key is a fuzzy match. */
|
||||
bool fuzzy_;
|
||||
};
|
||||
|
||||
class class_condition;
|
||||
|
||||
/**
|
||||
|
@ -413,21 +206,8 @@ public:
|
|||
max_ = o;
|
||||
}
|
||||
|
||||
void set_min(const std::string& s)
|
||||
{
|
||||
std::istringstream i(s);
|
||||
if(!(i >> min_)) {
|
||||
min_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void set_max(const std::string& s)
|
||||
{
|
||||
std::istringstream i(s);
|
||||
if(!(i >> max_)) {
|
||||
max_ = 0;
|
||||
}
|
||||
}
|
||||
void set_min(const std::string& s);
|
||||
void set_max(const std::string& s);
|
||||
|
||||
void set_super(const std::string& s)
|
||||
{
|
123
src/serialization/schema/type.cpp
Normal file
123
src/serialization/schema/type.cpp
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
Copyright (C) 2011 - 2018 by Sytyi Nick <nsytyi@gmail.com>
|
||||
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Implementation of type.hpp.
|
||||
*/
|
||||
|
||||
#include "serialization/schema/type.hpp"
|
||||
#include "boost/optional.hpp"
|
||||
|
||||
#include "config.hpp"
|
||||
|
||||
namespace schema_validation
|
||||
{
|
||||
|
||||
/*WIKI
|
||||
* @begin{parent}{name="wml_schema/tag/"}
|
||||
* @begin{tag}{name="key"}{min=0}{max=-1}
|
||||
* @begin{table}{config}
|
||||
* name & string & & The name of key. $
|
||||
* type & string & & The type of key value. $
|
||||
* default & string & & The default value of the key. $
|
||||
* mandatory & string & & Shows if key is mandatory $
|
||||
* @end{table}
|
||||
* @end{tag}{name="key"}
|
||||
* @end{parent}{name="wml_schema/tag/"}
|
||||
*/
|
||||
std::shared_ptr<class_type> class_type::from_config(const config& cfg)
|
||||
{
|
||||
boost::optional<config::const_child_itors> composite_range;
|
||||
std::shared_ptr<class_type> type;
|
||||
if(cfg.has_child("union")) {
|
||||
type = std::make_shared<class_type_union>(cfg["name"]);
|
||||
composite_range.emplace(cfg.child("union").child_range("type"));
|
||||
} else if(cfg.has_child("intersection")) {
|
||||
type = std::make_shared<class_type_intersection>(cfg["name"]);
|
||||
composite_range.emplace(cfg.child("intersection").child_range("type"));
|
||||
} else if(cfg.has_child("list")) {
|
||||
const config& list_cfg = cfg.child("list");
|
||||
int list_min = list_cfg["min"].to_int();
|
||||
int list_max = list_cfg["max"].str() == "infinite" ? -1 : list_cfg["max"].to_int(-1);
|
||||
if(list_max < 0) list_max = INT_MAX;
|
||||
type = std::make_shared<class_type_list>(cfg["name"], list_cfg["split"].str("\\s*,\\s*"), list_min, list_max);
|
||||
composite_range.emplace(list_cfg.child_range("element"));
|
||||
} else if(cfg.has_attribute("value")) {
|
||||
type = std::make_shared<class_type_simple>(cfg["name"], cfg["value"]);
|
||||
} else if(cfg.has_attribute("link")) {
|
||||
type = std::make_shared<class_type_alias>(cfg["name"], cfg["link"]);
|
||||
}
|
||||
if(composite_range) {
|
||||
auto composite_type = std::dynamic_pointer_cast<class_type_composite>(type);
|
||||
for(const config& elem : *composite_range) {
|
||||
composite_type->add_type(class_type::from_config(elem));
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
bool class_type_simple::matches(const std::string& value, const map&) const
|
||||
{
|
||||
boost::smatch sub;
|
||||
return boost::regex_match(value, sub, pattern_);
|
||||
}
|
||||
|
||||
bool class_type_alias::matches(const std::string& value, const map& type_map) const
|
||||
{
|
||||
if(!cached_) {
|
||||
auto it = type_map.find(link_);
|
||||
if(it == type_map.end()) {
|
||||
// TODO: Error message about the invalid type?
|
||||
return false;
|
||||
}
|
||||
cached_ = it->second;
|
||||
}
|
||||
return cached_->matches(value, type_map);
|
||||
}
|
||||
|
||||
bool class_type_union::matches(const std::string& value, const map& type_map) const
|
||||
{
|
||||
for(const auto& type : subtypes_) {
|
||||
if(type->matches(value, type_map)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool class_type_intersection::matches(const std::string& value, const map& type_map) const
|
||||
{
|
||||
for(const auto& type : subtypes_) {
|
||||
if(!type->matches(value, type_map)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool class_type_list::matches(const std::string& value, const map& type_map) const
|
||||
{
|
||||
boost::sregex_token_iterator it(value.begin(), value.end(), split_, -1), end;
|
||||
int n = 0;
|
||||
bool result = std::all_of(it, end, [this, &type_map, &n](const boost::ssub_match& match){
|
||||
// Not sure if this is necessary?
|
||||
if(!match.matched) return true;
|
||||
n++;
|
||||
return this->class_type_union::matches(std::string(match.first, match.second), type_map);
|
||||
});
|
||||
return result && n >= min_ && n <= max_;
|
||||
}
|
||||
|
||||
} // namespace schema_validation
|
120
src/serialization/schema/type.hpp
Normal file
120
src/serialization/schema/type.hpp
Normal file
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
Copyright (C) 2011 - 2018 by Sytyi Nick <nsytyi@gmail.com>
|
||||
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file contains object "type", which is used to store
|
||||
* information about types while annotation parsing.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
class config;
|
||||
|
||||
namespace schema_validation
|
||||
{
|
||||
|
||||
/**
|
||||
* Stores information about a schema type.
|
||||
* This is an abstract base class for several variants of schema type.
|
||||
*/
|
||||
class class_type {
|
||||
protected:
|
||||
std::string name_;
|
||||
public:
|
||||
class_type() = delete;
|
||||
explicit class_type(const std::string& name) : name_(name) {}
|
||||
using ptr = std::shared_ptr<class_type>;
|
||||
using map = std::map<std::string, ptr>;
|
||||
virtual bool matches(const std::string& value, const map& type_map) const = 0;
|
||||
static std::shared_ptr<class_type> from_config(const config& cfg);
|
||||
};
|
||||
|
||||
/**
|
||||
* Stores information about a schema type.
|
||||
* This type represents a simple pattern match.
|
||||
*/
|
||||
class class_type_simple : public class_type {
|
||||
boost::regex pattern_;
|
||||
public:
|
||||
class_type_simple(const std::string& name, const std::string& pattern) : class_type(name), pattern_(pattern) {}
|
||||
bool matches(const std::string& value, const map& type_map) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stores information about a schema type.
|
||||
* This type represents a name alias for another type.
|
||||
*/
|
||||
class class_type_alias : public class_type {
|
||||
mutable std::shared_ptr<class_type> cached_;
|
||||
std::string link_;
|
||||
public:
|
||||
class_type_alias(const std::string& name, const std::string& link) : class_type(name), link_(link) {}
|
||||
bool matches(const std::string& value, const map& type_map) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stores information about a schema type.
|
||||
* This is an abstract base class for composite types.
|
||||
*/
|
||||
class class_type_composite : public class_type {
|
||||
protected:
|
||||
std::vector<std::shared_ptr<class_type>> subtypes_;
|
||||
public:
|
||||
explicit class_type_composite(const std::string& name) : class_type(name) {}
|
||||
void add_type(std::shared_ptr<class_type> type)
|
||||
{
|
||||
subtypes_.push_back(type);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Stores information about a schema type.
|
||||
* Represents a union type, which matches if any of its subtypes match.
|
||||
*/
|
||||
class class_type_union : public class_type_composite {
|
||||
public:
|
||||
explicit class_type_union(const std::string& name) : class_type_composite(name) {}
|
||||
bool matches(const std::string& value, const map& type_map) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stores information about a schema type.
|
||||
* Represents an intersection type, which matches if all of its subtypes match.
|
||||
*/
|
||||
class class_type_intersection : public class_type_composite {
|
||||
public:
|
||||
explicit class_type_intersection(const std::string& name) : class_type_composite(name) {}
|
||||
bool matches(const std::string& value, const map& type_map) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stores information about a schema type.
|
||||
* Represents a list type, where each list element is itself a union.
|
||||
*/
|
||||
class class_type_list : public class_type_union {
|
||||
boost::regex split_;
|
||||
int min_ = 0, max_ = -1;
|
||||
public:
|
||||
class_type_list(const std::string& name, const std::string& pattern, int min, int max)
|
||||
: class_type_union(name)
|
||||
, split_(pattern)
|
||||
, min_(min)
|
||||
, max_(max)
|
||||
{}
|
||||
bool matches(const std::string& value, const map& type_map) const override;
|
||||
};
|
||||
}
|
|
@ -16,7 +16,9 @@
|
|||
|
||||
#include "config_cache.hpp"
|
||||
#include "serialization/parser.hpp"
|
||||
#include "serialization/tag.hpp"
|
||||
#include "serialization/schema/type.hpp"
|
||||
#include "serialization/schema/tag.hpp"
|
||||
#include "serialization/schema/key.hpp"
|
||||
#include "serialization/validator.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
|
Loading…
Add table
Reference in a new issue