Add types for leaves
Change-Id: Ibea2945920e523d2f3439eed2c12a5d719d178f1
diff --git a/src/ast_commands.cpp b/src/ast_commands.cpp
index a8b481d..9ef9044 100644
--- a/src/ast_commands.cpp
+++ b/src/ast_commands.cpp
@@ -7,6 +7,12 @@
*/
#include "ast_commands.hpp"
+enum_::enum_() = default;
+
+enum_::enum_(const std::string& value)
+ : m_value(value)
+{
+}
bool set_::operator==(const set_& b) const
{
@@ -18,6 +24,11 @@
return this->m_path == b.m_path;
}
+bool enum_::operator==(const enum_& b) const
+{
+ return this->m_value == b.m_value;
+}
+
bool create_::operator==(const create_& b) const
{
return this->m_path == b.m_path;
diff --git a/src/ast_commands.hpp b/src/ast_commands.hpp
index 5caeb2e..90af8ea 100644
--- a/src/ast_commands.hpp
+++ b/src/ast_commands.hpp
@@ -17,9 +17,12 @@
using x3::alnum;
using x3::alpha;
using x3::char_;
+using x3::double_;
using x3::expect;
+using x3::int_;
using x3::lexeme;
using x3::lit;
+using x3::uint_;
struct parser_context_tag;
@@ -40,10 +43,24 @@
path_ m_path;
};
+struct enum_ {
+ enum_();
+ enum_(const std::string& value);
+ bool operator==(const enum_& b) const;
+ std::string m_value;
+};
+
+using leaf_data_ = boost::variant<enum_,
+ double,
+ bool,
+ int32_t,
+ uint32_t,
+ std::string>;
+
struct set_ : x3::position_tagged {
bool operator==(const set_& b) const;
path_ m_path;
- std::string m_data;
+ leaf_data_ m_data;
};
using command_ = boost::variant<cd_, create_, delete_, set_>;
@@ -51,4 +68,5 @@
BOOST_FUSION_ADAPT_STRUCT(cd_, m_path)
BOOST_FUSION_ADAPT_STRUCT(create_, m_path)
BOOST_FUSION_ADAPT_STRUCT(delete_, m_path)
+BOOST_FUSION_ADAPT_STRUCT(enum_, m_value)
BOOST_FUSION_ADAPT_STRUCT(set_, m_path, m_data)
diff --git a/src/ast_handlers.hpp b/src/ast_handlers.hpp
index 0d3159b..848ce21 100644
--- a/src/ast_handlers.hpp
+++ b/src/ast_handlers.hpp
@@ -10,6 +10,7 @@
#include "parser_context.hpp"
#include "schema.hpp"
+#include "utils.hpp"
struct keyValue_class {
template <typename T, typename Iterator, typename Context>
@@ -90,7 +91,6 @@
if (parserContext.m_errorMsg.empty())
parserContext.m_errorMsg = "Expecting ']' here:";
return x3::error_handler_result::rethrow;
-
}
};
struct listElement_class {
@@ -110,7 +110,6 @@
} else {
return x3::error_handler_result::rethrow;
}
-
}
};
@@ -177,9 +176,6 @@
}
};
-struct data_string_class {
-};
-
struct cd_class {
template <typename T, typename Iterator, typename Context>
void on_success(Iterator const&, Iterator const&, T&, Context const&)
@@ -204,8 +200,7 @@
const auto& schema = parserContext.m_schema;
try {
container_ cont = boost::get<container_>(ast.m_path.m_nodes.back());
- path_ location{decltype(path_::m_nodes)(parserContext.m_curPath.m_nodes.begin(),
- parserContext.m_curPath.m_nodes.end() - 1)};
+ path_ location = pathWithoutLastNode(parserContext.m_curPath);
if (!schema.isPresenceContainer(location, cont.m_name)) {
parserContext.m_errorMsg = "This container is not a presence container.";
@@ -233,6 +228,89 @@
struct delete_class : public presenceContainerPathHandler {
};
+struct leaf_data_class {
+};
+
+struct leaf_data_base_class {
+ yang::LeafDataTypes m_type;
+
+ leaf_data_base_class(yang::LeafDataTypes type)
+ : m_type(type)
+ {
+ }
+
+ template <typename T, typename Iterator, typename Context>
+ void on_success(Iterator const&, Iterator const&, T&, Context const& context)
+ {
+ auto& parserContext = x3::get<parser_context_tag>(context);
+ auto& schema = parserContext.m_schema;
+
+ leaf_ leaf = boost::get<leaf_>(parserContext.m_curPath.m_nodes.back());
+ path_ location = pathWithoutLastNode(parserContext.m_curPath);
+
+ if (schema.leafType(location, leaf.m_name) != m_type) {
+ _pass(context) = false;
+ }
+ }
+};
+
+struct leaf_data_enum_class : leaf_data_base_class {
+ leaf_data_enum_class()
+ : leaf_data_base_class(yang::LeafDataTypes::Enum)
+ {
+ }
+
+ template <typename T, typename Iterator, typename Context>
+ void on_success(Iterator const& start, Iterator const& end, T& ast, Context const& context)
+ {
+ leaf_data_base_class::on_success(start, end, ast, context);
+ auto& parserContext = x3::get<parser_context_tag>(context);
+ auto& schema = parserContext.m_schema;
+
+ leaf_ leaf = boost::get<leaf_>(parserContext.m_curPath.m_nodes.back());
+ path_ location = pathWithoutLastNode(parserContext.m_curPath);
+
+ if (!schema.leafEnumHasValue(location, leaf.m_name, ast.m_value)) {
+ _pass(context) = false;
+ }
+ }
+};
+
+struct leaf_data_decimal_class : leaf_data_base_class {
+ leaf_data_decimal_class()
+ : leaf_data_base_class(yang::LeafDataTypes::Decimal)
+ {
+ }
+};
+
+struct leaf_data_bool_class : leaf_data_base_class {
+ leaf_data_bool_class()
+ : leaf_data_base_class(yang::LeafDataTypes::Bool)
+ {
+ }
+};
+
+struct leaf_data_int_class : leaf_data_base_class {
+ leaf_data_int_class()
+ : leaf_data_base_class(yang::LeafDataTypes::Int)
+ {
+ }
+};
+
+struct leaf_data_uint_class : leaf_data_base_class {
+ leaf_data_uint_class()
+ : leaf_data_base_class(yang::LeafDataTypes::Uint)
+ {
+ }
+};
+
+struct leaf_data_string_class : leaf_data_base_class {
+ leaf_data_string_class()
+ : leaf_data_base_class(yang::LeafDataTypes::String)
+ {
+ }
+};
+
struct set_class {
template <typename T, typename Iterator, typename Context>
void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
diff --git a/src/ast_path.cpp b/src/ast_path.cpp
index 2d2c600..2734377 100644
--- a/src/ast_path.cpp
+++ b/src/ast_path.cpp
@@ -69,7 +69,7 @@
std::experimental::make_ostream_joiner(res, ' '),
[] (const auto& it) { return it.first + "=" + it.second; });
res << "]";
- return res.str();
+ return res.str();
}
std::string operator()(const nodeup_&) const
{
diff --git a/src/grammars.hpp b/src/grammars.hpp
index ab410c8..443b28d 100644
--- a/src/grammars.hpp
+++ b/src/grammars.hpp
@@ -21,7 +21,15 @@
x3::rule<container_class, container_> const container = "container";
x3::rule<leaf_class, leaf_> const leaf = "leaf";
x3::rule<path_class, path_> const path = "path";
-x3::rule<data_string_class, std::string> const data_string = "data_string";
+
+x3::rule<leaf_data_class, leaf_data_> const leaf_data = "leaf_data";
+x3::rule<leaf_data_enum_class, enum_> const leaf_data_enum = "leaf_data_enum";
+x3::rule<leaf_data_decimal_class, double> const leaf_data_decimal = "leaf_data_decimal";
+x3::rule<leaf_data_bool_class, bool> const leaf_data_bool = "leaf_data_bool";
+x3::rule<leaf_data_int_class, int32_t> const leaf_data_int = "leaf_data_int";
+x3::rule<leaf_data_uint_class, uint32_t> const leaf_data_uint = "leaf_data_uint";
+x3::rule<leaf_data_string_class, std::string> const leaf_data_string = "leaf_data_string";
+
x3::rule<cd_class, cd_> const cd = "cd";
x3::rule<set_class, set_> const set = "set";
x3::rule<create_class, create_> const create = "create";
@@ -64,8 +72,36 @@
auto const path_def =
(x3::expect[container | listElement | nodeup | leaf]) % '/';
-auto const data_string_def =
- lexeme[+char_];
+auto const leaf_data_enum_def =
+ +char_;
+auto const leaf_data_decimal_def =
+ double_;
+
+struct bool_symbol_table : x3::symbols<bool> {
+ bool_symbol_table()
+ {
+ add
+ ("true", true)
+ ("false", false);
+ }
+} const bool_rule;
+
+auto const leaf_data_bool_def =
+ bool_rule;
+auto const leaf_data_int_def =
+ int_;
+auto const leaf_data_uint_def =
+ uint_;
+auto const leaf_data_string_def =
+ *char_;
+
+auto const leaf_data_def =
+ leaf_data_enum |
+ leaf_data_decimal |
+ leaf_data_bool |
+ leaf_data_int |
+ leaf_data_uint |
+ leaf_data_string;
auto const space_separator =
x3::omit[x3::no_skip[space]];
@@ -80,7 +116,7 @@
lit("delete") >> space_separator > path;
auto const set_def =
- lit("set") >> space_separator > path > data_string;
+ lit("set") >> space_separator > path > leaf_data;
auto const command_def =
x3::expect[cd | create | delete_rule | set] >> x3::eoi;
@@ -98,7 +134,13 @@
BOOST_SPIRIT_DEFINE(container)
BOOST_SPIRIT_DEFINE(leaf)
BOOST_SPIRIT_DEFINE(path)
-BOOST_SPIRIT_DEFINE(data_string)
+BOOST_SPIRIT_DEFINE(leaf_data)
+BOOST_SPIRIT_DEFINE(leaf_data_enum)
+BOOST_SPIRIT_DEFINE(leaf_data_decimal)
+BOOST_SPIRIT_DEFINE(leaf_data_bool)
+BOOST_SPIRIT_DEFINE(leaf_data_int)
+BOOST_SPIRIT_DEFINE(leaf_data_uint)
+BOOST_SPIRIT_DEFINE(leaf_data_string)
BOOST_SPIRIT_DEFINE(set)
BOOST_SPIRIT_DEFINE(cd)
BOOST_SPIRIT_DEFINE(create)
diff --git a/src/interpreter.cpp b/src/interpreter.cpp
index 934aac9..1a4e84a 100644
--- a/src/interpreter.cpp
+++ b/src/interpreter.cpp
@@ -9,9 +9,23 @@
#include <iostream>
#include "interpreter.hpp"
+struct leafDataToString : boost::static_visitor<std::string> {
+ std::string operator()(const enum_& data) const
+ {
+ return data.m_value;
+ }
+ template <typename T>
+ std::string operator()(const T& data) const
+ {
+ std::stringstream stream;
+ stream << data;
+ return stream.str();
+ }
+};
+
void Interpreter::operator()(const set_& set) const
{
- std::cout << "Setting " << pathToDataString(set.m_path) << " to " << set.m_data << std::endl;
+ std::cout << "Setting " << pathToDataString(set.m_path) << " to " << boost::apply_visitor(leafDataToString(), set.m_data) << std::endl;
}
void Interpreter::operator()(const cd_& cd) const
diff --git a/src/main.cpp b/src/main.cpp
index df4c925..e498db0 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -49,9 +49,14 @@
Schema schema;
schema.addContainer("", "a", yang::ContainerTraits::Presence);
schema.addContainer("", "b");
- schema.addLeaf("", "leaf");
+ schema.addLeaf("", "leafString", yang::LeafDataTypes::String);
+ schema.addLeaf("", "leafDecimal", yang::LeafDataTypes::Decimal);
+ schema.addLeaf("", "leafBool", yang::LeafDataTypes::Bool);
+ schema.addLeaf("", "leafInt", yang::LeafDataTypes::Int);
+ schema.addLeaf("", "leafUint", yang::LeafDataTypes::Uint);
+ schema.addLeafEnum("", "leafEnum", {"lol", "data", "coze"});
schema.addContainer("a", "a2");
- schema.addLeaf("a", "leafa");
+ schema.addLeaf("a", "leafa", yang::LeafDataTypes::String);
schema.addContainer("b", "b2", yang::ContainerTraits::Presence);
schema.addContainer("a/a2", "a3", yang::ContainerTraits::Presence);
schema.addContainer("b/b2", "b3");
diff --git a/src/schema.cpp b/src/schema.cpp
index 95cd4ae..066dc3b 100644
--- a/src/schema.cpp
+++ b/src/schema.cpp
@@ -96,9 +96,24 @@
return boost::get<yang::container>(children(locationString).at(name)).m_presence == yang::ContainerTraits::Presence;
}
-void Schema::addLeaf(const std::string& location, const std::string& name)
+void Schema::addLeaf(const std::string& location, const std::string& name, const yang::LeafDataTypes& type)
{
- m_nodes.at(location).emplace(name, yang::leaf{});
+ m_nodes.at(location).emplace(name, yang::leaf{type, {}});
+}
+
+void Schema::addLeafEnum(const std::string& location, const std::string& name, std::set<std::string> enumValues)
+{
+ m_nodes.at(location).emplace(name, yang::leaf{yang::LeafDataTypes::Enum, enumValues});
+}
+
+bool Schema::leafEnumHasValue(const path_& location, const std::string& name, const std::string& value) const
+{
+ std::string locationString = pathToSchemaString(location);
+ assert(isLeaf(location, name));
+
+ const auto& child = children(locationString).at(name);
+ const auto& list = boost::get<yang::leaf>(child);
+ return list.m_enumValues.find(value) != list.m_enumValues.end();
}
bool Schema::isLeaf(const path_& location, const std::string& name) const
@@ -109,3 +124,9 @@
return children(locationString).at(name).type() == typeid(yang::leaf);
}
+
+yang::LeafDataTypes Schema::leafType(const path_& location, const std::string& name) const
+{
+ std::string locationString = pathToSchemaString(location);
+ return boost::get<yang::leaf>(children(locationString).at(name)).m_type;
+}
diff --git a/src/schema.hpp b/src/schema.hpp
index 73e89df..e87619b 100644
--- a/src/schema.hpp
+++ b/src/schema.hpp
@@ -19,6 +19,16 @@
Presence,
None,
};
+
+enum class LeafDataTypes {
+ String,
+ Decimal,
+ Bool,
+ Int,
+ Uint,
+ Enum,
+};
+
struct container {
yang::ContainerTraits m_presence;
};
@@ -26,6 +36,8 @@
std::set<std::string> m_keys;
};
struct leaf {
+ yang::LeafDataTypes m_type;
+ std::set<std::string> m_enumValues;
};
}
@@ -54,8 +66,11 @@
bool isList(const path_& location, const std::string& name) const;
void addList(const std::string& location, const std::string& name, const std::set<std::string>& keys);
bool isPresenceContainer(const path_& location, const std::string& name) const;
- void addLeaf(const std::string& location, const std::string& name);
+ void addLeaf(const std::string& location, const std::string& name, const yang::LeafDataTypes& type);
+ void addLeafEnum(const std::string& location, const std::string& name, std::set<std::string> enumValues);
+ bool leafEnumHasValue(const path_& location, const std::string& name, const std::string& value) const;
bool isLeaf(const path_& location, const std::string& name) const;
+ yang::LeafDataTypes leafType(const path_& location, const std::string& name) const;
private:
const std::unordered_map<std::string, NodeType>& children(const std::string& name) const;
diff --git a/src/utils.cpp b/src/utils.cpp
index 77466c4..a7fea46 100644
--- a/src/utils.cpp
+++ b/src/utils.cpp
@@ -25,3 +25,8 @@
res.erase(pos);
return res;
}
+
+path_ pathWithoutLastNode(const path_& path)
+{
+ return path_{decltype(path_::m_nodes)(path.m_nodes.begin(), path.m_nodes.end() - 1)};
+}
diff --git a/src/utils.hpp b/src/utils.hpp
index 4f10102..2c550d7 100644
--- a/src/utils.hpp
+++ b/src/utils.hpp
@@ -6,6 +6,8 @@
*
*/
#include <string>
+#include "ast_path.hpp"
std::string joinPaths(const std::string& prefix, const std::string& suffix);
std::string stripLastNodeFromPath(const std::string& path);
+path_ pathWithoutLastNode(const path_& path);
diff --git a/tests/leaf_editing.cpp b/tests/leaf_editing.cpp
index 5894921..09e8504 100644
--- a/tests/leaf_editing.cpp
+++ b/tests/leaf_editing.cpp
@@ -15,10 +15,15 @@
{
Schema schema;
schema.addContainer("", "contA");
- schema.addLeaf("", "leaf");
- schema.addLeaf("contA", "leafInCont");
+ schema.addLeaf("", "leafString", yang::LeafDataTypes::String);
+ schema.addLeaf("", "leafDecimal", yang::LeafDataTypes::Decimal);
+ schema.addLeaf("", "leafBool", yang::LeafDataTypes::Bool);
+ schema.addLeaf("", "leafInt", yang::LeafDataTypes::Int);
+ schema.addLeaf("", "leafUint", yang::LeafDataTypes::Uint);
+ schema.addLeafEnum("", "leafEnum", {"lol", "data", "coze"});
+ schema.addLeaf("contA", "leafInCont", yang::LeafDataTypes::String);
schema.addList("", "list", {"number"});
- schema.addLeaf("list", "leafInList");
+ schema.addLeaf("list", "leafInList", yang::LeafDataTypes::String);
Parser parser(schema);
std::string input;
std::ostringstream errorStream;
@@ -27,11 +32,11 @@
{
set_ expected;
- SECTION("set leaf some_data")
+ SECTION("set leafString some_data")
{
- input = "set leaf some_data";
- expected.m_path.m_nodes.push_back(leaf_("leaf"));
- expected.m_data = "some_data";
+ input = "set leafString some_data";
+ expected.m_path.m_nodes.push_back(leaf_("leafString"));
+ expected.m_data = std::string("some_data");
}
SECTION("set contA/leafInCont more_data")
@@ -39,7 +44,55 @@
input = "set contA/leafInCont more_data";
expected.m_path.m_nodes.push_back(container_("contA"));
expected.m_path.m_nodes.push_back(leaf_("leafInCont"));
- expected.m_data = "more_data";
+ expected.m_data = std::string("more_data");
+ }
+
+ SECTION("set list[number=1]/leafInList another_data")
+ {
+ input = "set list[number=1]/leafInList another_data";
+ auto keys = std::map<std::string, std::string>{
+ {"number", "1"}};
+ expected.m_path.m_nodes.push_back(listElement_("list", keys));
+ expected.m_path.m_nodes.push_back(leaf_("leafInList"));
+ expected.m_data = std::string("another_data");
+ }
+
+ SECTION("data types")
+ {
+ SECTION("string")
+ {
+ input = "set leafString somedata";
+ expected.m_path.m_nodes.push_back(leaf_("leafString"));
+ expected.m_data = std::string("somedata");
+ }
+
+ SECTION("int")
+ {
+ input = "set leafInt 2";
+ expected.m_path.m_nodes.push_back(leaf_("leafInt"));
+ expected.m_data = 2;
+ }
+
+ SECTION("decimal")
+ {
+ input = "set leafDecimal 3.14159";
+ expected.m_path.m_nodes.push_back(leaf_("leafDecimal"));
+ expected.m_data = 3.14159;
+ }
+
+ SECTION("enum")
+ {
+ input = "set leafEnum coze";
+ expected.m_path.m_nodes.push_back(leaf_("leafEnum"));
+ expected.m_data = enum_("coze");
+ }
+
+ SECTION("bool")
+ {
+ input = "set leafBool true";
+ expected.m_path.m_nodes.push_back(leaf_("leafBool"));
+ expected.m_data = true;
+ }
}
command_ command = parser.parseCommand(input, errorStream);
@@ -78,6 +131,26 @@
}
}
+ SECTION("wrong types")
+ {
+ SECTION("set leafBool blabla")
+ {
+ input = "set leafBool blabla";
+ }
+ SECTION("set leafUint blabla")
+ {
+ input = "set leafUint blabla";
+ }
+ SECTION("set leafInt blabla")
+ {
+ input = "set leafInt blabla";
+ }
+ SECTION("set leafEnum blabla")
+ {
+ input = "set leafEnum blabla";
+ }
+ }
+
REQUIRE_THROWS(parser.parseCommand(input, errorStream));
}
}
diff --git a/tests/presence_containers.cpp b/tests/presence_containers.cpp
index 72c9daf..8958627 100644
--- a/tests/presence_containers.cpp
+++ b/tests/presence_containers.cpp
@@ -33,19 +33,19 @@
SECTION("a")
{
input = "a";
- expectedPath.m_nodes = { container_("a") };
+ expectedPath.m_nodes = {container_("a")};
}
SECTION("b/b2")
{
input = "b/b2";
- expectedPath.m_nodes = { container_("b"), container_("b2") };
+ expectedPath.m_nodes = {container_("b"), container_("b2")};
}
SECTION("a/a2/a3")
{
input = "a/a2/a3";
- expectedPath.m_nodes = { container_("a"), container_("a2"), container_("a3") };
+ expectedPath.m_nodes = {container_("a"), container_("a2"), container_("a3")};
}
SECTION("list[quote=lol]/contInList")
@@ -53,7 +53,7 @@
input = "list[quote=lol]/contInList";
auto keys = std::map<std::string, std::string>{
{"quote", "lol"}};
- expectedPath.m_nodes = { listElement_("list", keys), container_("contInList") };
+ expectedPath.m_nodes = {listElement_("list", keys), container_("contInList")};
}
create_ expectedCreate;