blob: e6164981e709ec35e260d52094dea7280b2547f9 [file] [log] [blame]
Václav Kubernát9ae8cc42020-03-25 19:17:41 +01001/*
2 * Copyright (C) 2020 CESNET, https://photonics.cesnet.cz/
3 *
4 * Written by Václav Kubernát <kubernat@cesnet.cz>
5 *
6*/
7
8#pragma once
9
10#include <boost/spirit/home/x3.hpp>
Václav Kubernát9ae8cc42020-03-25 19:17:41 +010011#include "ast_handlers.hpp"
12#include "common_parsers.hpp"
Václav Kubernát3a99f002020-03-31 02:27:41 +020013#include "leaf_data_type.hpp"
Václav Kubernát9ae8cc42020-03-25 19:17:41 +010014#include "schema.hpp"
15namespace x3 = boost::spirit::x3;
16
Václav Kubernát3a99f002020-03-31 02:27:41 +020017template <typename TYPE>
Václav Kubernát882174d2020-03-25 21:31:46 +010018struct leaf_data_class;
Václav Kubernát9ae8cc42020-03-25 19:17:41 +010019
Václav Kubernát3a99f002020-03-31 02:27:41 +020020x3::rule<struct leaf_data_class<yang::Enum>, enum_> const leaf_data_enum = "leaf_data_enum";
21x3::rule<struct leaf_data_class<yang::IdentityRef>, identityRef_> const leaf_data_identityRef = "leaf_data_identityRef";
22x3::rule<struct leaf_data_class<yang::Binary>, binary_> const leaf_data_binary = "leaf_data_binary";
23x3::rule<struct leaf_data_class<yang::Decimal>, double> const leaf_data_decimal = "leaf_data_decimal";
24x3::rule<struct leaf_data_class<yang::String>, std::string> const leaf_data_string = "leaf_data_string";
Václav Kubernát9ae8cc42020-03-25 19:17:41 +010025
Václav Kubernát882174d2020-03-25 21:31:46 +010026using x3::char_;
27
Václav Kubernát9ae8cc42020-03-25 19:17:41 +010028auto const leaf_data_enum_def =
Václav Kubernát3a99f002020-03-31 02:27:41 +020029 +char_;
Václav Kubernát9ae8cc42020-03-25 19:17:41 +010030
Václav Kubernát9ae8cc42020-03-25 19:17:41 +010031struct bool_symbol_table : x3::symbols<bool> {
32 bool_symbol_table()
33 {
Václav Kubernát3a99f002020-03-31 02:27:41 +020034 add
35 ("true", true)
36 ("false", false);
Václav Kubernát9ae8cc42020-03-25 19:17:41 +010037 }
Václav Kubernát882174d2020-03-25 21:31:46 +010038} const bool_symbols;
Václav Kubernát9ae8cc42020-03-25 19:17:41 +010039
Václav Kubernát9ae8cc42020-03-25 19:17:41 +010040auto const leaf_data_string_def =
41 '\'' >> *(char_-'\'') >> '\'' |
42 '\"' >> *(char_-'\"') >> '\"';
43
Václav Kubernát9ae8cc42020-03-25 19:17:41 +010044auto const leaf_data_binary_def =
Václav Kubernáte118f002020-05-14 22:54:13 +020045 as<std::string>[+(x3::alnum | char_('+') | char_('/')) >> -char_('=') >> -char_('=')];
Václav Kubernát9ae8cc42020-03-25 19:17:41 +010046
Václav Kubernát9ae8cc42020-03-25 19:17:41 +010047auto const leaf_data_identityRef_def =
Václav Kubernáte7f62ae2020-05-14 22:57:53 +020048 -module >> node_identifier;
Václav Kubernát3a99f002020-03-31 02:27:41 +020049
50template <typename It, typename Ctx, typename RCtx, typename Attr>
51struct impl_LeafData {
52 It& first;
53 It last;
54 Ctx const& ctx;
55 RCtx& rctx;
56 Attr& attr;
57 ParserContext& parserContext;
58
59 bool operator()(const yang::Binary&) const
60 {
61 return leaf_data_binary.parse(first, last, ctx, rctx, attr);
62 }
63 bool operator()(const yang::Bool&) const
64 {
65 return bool_symbols.parse(first, last, ctx, rctx, attr);
66 }
67 bool operator()(const yang::Decimal&) const
68 {
69 return x3::double_.parse(first, last, ctx, rctx, attr);
70 }
71 bool operator()(const yang::Uint8&) const
72 {
73 return x3::uint8.parse(first, last, ctx, rctx, attr);
74 }
75 bool operator()(const yang::Uint16&) const
76 {
77 return x3::uint16.parse(first, last, ctx, rctx, attr);
78 }
79 bool operator()(const yang::Uint32&) const
80 {
81 return x3::uint32.parse(first, last, ctx, rctx, attr);
82 }
83 bool operator()(const yang::Uint64&) const
84 {
85 return x3::uint64.parse(first, last, ctx, rctx, attr);
86 }
87 bool operator()(const yang::Int8&) const
88 {
89 return x3::int8.parse(first, last, ctx, rctx, attr);
90 }
91 bool operator()(const yang::Int16&) const
92 {
93 return x3::int16.parse(first, last, ctx, rctx, attr);
94 }
95 bool operator()(const yang::Int32&) const
96 {
97 return x3::int32.parse(first, last, ctx, rctx, attr);
98 }
99 bool operator()(const yang::Int64&) const
100 {
101 return x3::int64.parse(first, last, ctx, rctx, attr);
102 }
103 bool operator()(const yang::String&) const
104 {
105 return leaf_data_string.parse(first, last, ctx, rctx, attr);
106 }
Jan Kundrát379bb572020-05-07 03:23:13 +0200107 bool operator()(const yang::Empty) const
108 {
109 return x3::attr(empty_{}).parse(first, last, ctx, rctx, attr);
110 }
Václav Kubernát3a99f002020-03-31 02:27:41 +0200111 template <typename Type>
112 void createSetSuggestions(const Type& type) const
113 {
114 parserContext.m_suggestions.clear();
115 std::transform(type.m_allowedValues.begin(),
116 type.m_allowedValues.end(),
117 std::inserter(parserContext.m_suggestions, parserContext.m_suggestions.end()),
Václav Kubernát549b08f2020-05-14 22:19:36 +0200118 [](auto it) {
119 std::string res;
120 if constexpr (std::is_same<Type, yang::IdentityRef>()) {
121 res = it.m_prefix ? it.m_prefix->m_name + ":" : "";
122 }
123 res += it.m_value;
124 return Completion{res};
125 });
Václav Kubernát3a99f002020-03-31 02:27:41 +0200126 parserContext.m_completionIterator = first;
127 }
128 bool operator()(const yang::Enum& type) const
129 {
130 createSetSuggestions(type);
Václav Kubernáta68c0ef2020-05-07 10:32:56 +0200131 auto checkValidEnum = [this, type] (auto& ctx) {
132 if (type.m_allowedValues.count(boost::get<enum_>(attr)) == 0) {
133 _pass(ctx) = false;
134 parserContext.m_errorMsg = "leaf data type mismatch: Expected an enum here. Allowed values:";
135 for (const auto& it : type.m_allowedValues) {
136 parserContext.m_errorMsg += " " + it.m_value;
137 }
Václav Kubernát3a99f002020-03-31 02:27:41 +0200138 }
Václav Kubernáta68c0ef2020-05-07 10:32:56 +0200139 };
140 return leaf_data_enum[checkValidEnum].parse(first, last, ctx, rctx, attr);
Václav Kubernát3a99f002020-03-31 02:27:41 +0200141 }
142 bool operator()(const yang::IdentityRef& type) const
143 {
144 createSetSuggestions(type);
Václav Kubernáta68c0ef2020-05-07 10:32:56 +0200145 auto checkValidIdentity = [this, type] (auto& ctx) {
146 identityRef_ pair{boost::get<identityRef_>(_attr(ctx))};
147 if (!pair.m_prefix) {
148 pair.m_prefix = module_{parserContext.currentSchemaPath().m_nodes.front().m_prefix.get().m_name};
149 }
150 _pass(ctx) = type.m_allowedValues.count(pair) != 0;
151 };
152
153 return leaf_data_identityRef[checkValidIdentity].parse(first, last, ctx, rctx, attr);
Václav Kubernát3a99f002020-03-31 02:27:41 +0200154 }
155 bool operator()(const yang::LeafRef& leafRef) const
156 {
Václav Kubernát13b23d72020-04-16 21:49:51 +0200157 return std::visit(*this, leafRef.m_targetType->m_type);
Václav Kubernát3a99f002020-03-31 02:27:41 +0200158 }
Václav Kubernát2984f442020-02-20 17:43:35 +0100159 bool operator()(const yang::Union& unionInfo) const
160 {
161 return std::any_of(unionInfo.m_unionTypes.begin(), unionInfo.m_unionTypes.end(), [this](const auto& type) {
Václav Kubernát13b23d72020-04-16 21:49:51 +0200162 return std::visit(*this, type.m_type);
Václav Kubernát2984f442020-02-20 17:43:35 +0100163 });
164 }
Václav Kubernát3a99f002020-03-31 02:27:41 +0200165};
Václav Kubernát9ae8cc42020-03-25 19:17:41 +0100166
Václav Kubernát882174d2020-03-25 21:31:46 +0100167struct LeafData : x3::parser<LeafData> {
168 using attribute_type = leaf_data_;
Václav Kubernát9ae8cc42020-03-25 19:17:41 +0100169
Václav Kubernát882174d2020-03-25 21:31:46 +0100170 // TODO: Can this be placed in a .cpp file?
171 template <typename It, typename Ctx, typename RCtx, typename Attr>
172 bool parse(It& first, It last, Ctx const& ctx, RCtx& rctx, Attr& attr) const
173 {
174 ParserContext& parserContext = x3::get<parser_context_tag>(ctx);
175 const Schema& schema = parserContext.m_schema;
Václav Kubernát13b23d72020-04-16 21:49:51 +0200176 auto type = schema.leafType(parserContext.m_tmpListKeyLeafPath.m_location, parserContext.m_tmpListKeyLeafPath.m_node).m_type;
Václav Kubernát882174d2020-03-25 21:31:46 +0100177
Václav Kubernát3a99f002020-03-31 02:27:41 +0200178 auto pass = std::visit(impl_LeafData<It, Ctx, RCtx, Attr>{first, last, ctx, rctx, attr, parserContext}, type);
Václav Kubernát882174d2020-03-25 21:31:46 +0100179
180 if (!pass) {
181 if (parserContext.m_errorMsg.empty()) {
Václav Kubernát13b23d72020-04-16 21:49:51 +0200182 parserContext.m_errorMsg = "leaf data type mismatch: Expected " + leafDataTypeToString(type) + " here:";
Václav Kubernát882174d2020-03-25 21:31:46 +0100183 }
184 }
185 return pass;
186 }
187};
188
Václav Kubernátf92724b2020-07-08 17:58:22 +0200189auto const leaf_data = x3::no_skip[LeafData()];
Václav Kubernát882174d2020-03-25 21:31:46 +0100190
Václav Kubernát9ae8cc42020-03-25 19:17:41 +0100191BOOST_SPIRIT_DEFINE(leaf_data_enum)
Václav Kubernát9ae8cc42020-03-25 19:17:41 +0100192BOOST_SPIRIT_DEFINE(leaf_data_string)
Václav Kubernát9ae8cc42020-03-25 19:17:41 +0100193BOOST_SPIRIT_DEFINE(leaf_data_binary)
Václav Kubernát9ae8cc42020-03-25 19:17:41 +0100194BOOST_SPIRIT_DEFINE(leaf_data_identityRef)