blob: bbacbea8df8570e70c51f95da5a64678d9fe32e2 [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>
11#include "ast_values.hpp"
12#include "ast_handlers.hpp"
13#include "common_parsers.hpp"
14#include "schema.hpp"
15namespace x3 = boost::spirit::x3;
16
Václav Kubernát882174d2020-03-25 21:31:46 +010017template <yang::LeafDataTypes TYPE>
18struct leaf_data_class;
Václav Kubernát9ae8cc42020-03-25 19:17:41 +010019
Václav Kubernát882174d2020-03-25 21:31:46 +010020template <yang::LeafDataTypes TYPE>
21struct createSetSuggestions_class {
22 std::set<std::string> getSuggestions(const ParserContext& ctx, const Schema& schema) const;
23
24 template <typename T, typename Iterator, typename Context>
25 void on_success(Iterator const& begin, Iterator const&, T&, Context const& context)
26 {
27 auto& parserContext = x3::get<parser_context_tag>(context);
28 const Schema& schema = parserContext.m_schema;
29
30 // Only generate completions if the type is correct so that we don't
31 // overwrite some other completions.
32 if (schema.leafType(parserContext.m_tmpListKeyLeafPath.m_location, parserContext.m_tmpListKeyLeafPath.m_node) == TYPE) {
33 parserContext.m_completionIterator = begin;
34 auto suggestions = getSuggestions(parserContext, schema);
35 std::set<Completion> res;
36 std::transform(suggestions.begin(), suggestions.end(), std::inserter(res, res.end()), [](auto it) { return Completion{it}; });
37 parserContext.m_suggestions = res;
38 }
39 }
40};
41
42template <>
43struct leaf_data_class<yang::LeafDataTypes::Enum> {
44 template <typename T, typename Iterator, typename Context>
45 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
46 {
47 if (_pass(context) == false)
48 return;
49 auto& parserContext = x3::get<parser_context_tag>(context);
50 auto& schema = parserContext.m_schema;
51
52 if (!schema.leafEnumHasValue(parserContext.m_tmpListKeyLeafPath.m_location, parserContext.m_tmpListKeyLeafPath.m_node, ast.m_value)) {
53 _pass(context) = false;
54 parserContext.m_errorMsg = "leaf data type mismatch: Expected an enum here. Allowed values:";
55 for (const auto& it : schema.enumValues(parserContext.m_tmpListKeyLeafPath.m_location, parserContext.m_tmpListKeyLeafPath.m_node)) {
56 parserContext.m_errorMsg += " " + it;
57 }
58 }
59 }
60};
61
62template <>
63struct leaf_data_class<yang::LeafDataTypes::IdentityRef> {
64 template <typename T, typename Iterator, typename Context>
65 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
66 {
67 auto& parserContext = x3::get<parser_context_tag>(context);
68 auto& schema = parserContext.m_schema;
69
70 ModuleValuePair pair;
71 if (ast.m_prefix) {
72 pair.first = ast.m_prefix.get().m_name;
73 }
74 pair.second = ast.m_value;
75
76 if (!schema.leafIdentityIsValid(parserContext.m_tmpListKeyLeafPath.m_location, parserContext.m_tmpListKeyLeafPath.m_node, pair)) {
77 _pass(context) = false;
78 }
79 }
80};
81
82x3::rule<leaf_data_class<yang::LeafDataTypes::Enum>, enum_> const leaf_data_enum = "leaf_data_enum";
83x3::rule<leaf_data_class<yang::LeafDataTypes::IdentityRef>, identityRef_> const leaf_data_identityRef = "leaf_data_identityRef";
84x3::rule<struct leaf_data_class<yang::LeafDataTypes::Binary>, binary_> const leaf_data_binary = "leaf_data_binary";
85x3::rule<struct leaf_data_class<yang::LeafDataTypes::Decimal>, double> const leaf_data_decimal = "leaf_data_decimal";
86x3::rule<struct leaf_data_class<yang::LeafDataTypes::String>, std::string> const leaf_data_string = "leaf_data_string";
87x3::rule<struct leaf_data_class_binary, std::string> const leaf_data_binary_data = "leaf_data_binary_data";
88x3::rule<struct leaf_data_identityRef_data_class, identityRef_> const leaf_data_identityRef_data = "leaf_data_identityRef_data";
Václav Kubernát9ae8cc42020-03-25 19:17:41 +010089
90x3::rule<createSetSuggestions_class<yang::LeafDataTypes::Enum>, x3::unused_type> const createEnumSuggestions = "createEnumSuggestions";
91x3::rule<createSetSuggestions_class<yang::LeafDataTypes::IdentityRef>, x3::unused_type> const createIdentitySuggestions = "createIdentitySuggestions";
92
Václav Kubernát882174d2020-03-25 21:31:46 +010093using x3::char_;
94
Václav Kubernát9ae8cc42020-03-25 19:17:41 +010095auto const createEnumSuggestions_def =
96 x3::eps;
97
98auto const leaf_data_enum_def =
99 createEnumSuggestions >> +char_;
100
Václav Kubernát9ae8cc42020-03-25 19:17:41 +0100101struct bool_symbol_table : x3::symbols<bool> {
102 bool_symbol_table()
103 {
104 add
105 ("true", true)
106 ("false", false);
107 }
Václav Kubernát882174d2020-03-25 21:31:46 +0100108} const bool_symbols;
Václav Kubernát9ae8cc42020-03-25 19:17:41 +0100109
Václav Kubernát9ae8cc42020-03-25 19:17:41 +0100110auto const leaf_data_string_def =
111 '\'' >> *(char_-'\'') >> '\'' |
112 '\"' >> *(char_-'\"') >> '\"';
113
114// This intermediate rule is neccessary for coercing to std::string.
Václav Kubernát882174d2020-03-25 21:31:46 +0100115// TODO: check if I can do the coercing right in the grammar with `as{}` from
116// https://github.com/boostorg/spirit/issues/530#issuecomment-584836532
117// This would shave off some more lines.
Václav Kubernát9ae8cc42020-03-25 19:17:41 +0100118auto const leaf_data_binary_data_def =
119 +(x3::alnum | char_('+') | char_('/')) >> -char_('=') >> -char_('=');
120
121auto const leaf_data_binary_def =
122 leaf_data_binary_data;
123
124auto const leaf_data_identityRef_data_def =
125 -module >> node_identifier;
126
127auto const createIdentitySuggestions_def =
128 x3::eps;
129
130auto const leaf_data_identityRef_def =
131 createIdentitySuggestions >> leaf_data_identityRef_data;
132
Václav Kubernát882174d2020-03-25 21:31:46 +0100133struct LeafData : x3::parser<LeafData> {
134 using attribute_type = leaf_data_;
Václav Kubernát9ae8cc42020-03-25 19:17:41 +0100135
Václav Kubernát882174d2020-03-25 21:31:46 +0100136 // TODO: Can this be placed in a .cpp file?
137 template <typename It, typename Ctx, typename RCtx, typename Attr>
138 bool parse(It& first, It last, Ctx const& ctx, RCtx& rctx, Attr& attr) const
139 {
140 ParserContext& parserContext = x3::get<parser_context_tag>(ctx);
141 const Schema& schema = parserContext.m_schema;
142 auto type = schema.leafType(parserContext.m_tmpListKeyLeafPath.m_location, parserContext.m_tmpListKeyLeafPath.m_node);
143
144 std::function<bool(yang::LeafDataTypes)> parse_impl = [&](auto type) {
145 switch (type) {
146 case yang::LeafDataTypes::Binary:
147 return leaf_data_binary.parse(first, last, ctx, rctx, attr);
148 case yang::LeafDataTypes::Bool:
149 return bool_symbols.parse(first, last, ctx, rctx, attr);
150 case yang::LeafDataTypes::Decimal:
151 return x3::double_.parse(first, last, ctx, rctx, attr);
152 case yang::LeafDataTypes::Uint8:
153 return x3::uint8.parse(first, last, ctx, rctx, attr);
154 case yang::LeafDataTypes::Uint16:
155 return x3::uint16.parse(first, last, ctx, rctx, attr);
156 case yang::LeafDataTypes::Uint32:
157 return x3::uint32.parse(first, last, ctx, rctx, attr);
158 case yang::LeafDataTypes::Uint64:
159 return x3::uint64.parse(first, last, ctx, rctx, attr);
160 case yang::LeafDataTypes::Int8:
161 return x3::int8.parse(first, last, ctx, rctx, attr);
162 case yang::LeafDataTypes::Int16:
163 return x3::int16.parse(first, last, ctx, rctx, attr);
164 case yang::LeafDataTypes::Int32:
165 return x3::int32.parse(first, last, ctx, rctx, attr);
166 case yang::LeafDataTypes::Int64:
167 return x3::int64.parse(first, last, ctx, rctx, attr);
168 case yang::LeafDataTypes::String:
169 return leaf_data_string.parse(first, last, ctx, rctx, attr);
170 case yang::LeafDataTypes::Enum:
171 return leaf_data_enum.parse(first, last, ctx, rctx, attr);
172 case yang::LeafDataTypes::IdentityRef:
173 return leaf_data_identityRef.parse(first, last, ctx, rctx, attr);
174 case yang::LeafDataTypes::LeafRef:
175 auto actualType = schema.leafrefBaseType(parserContext.m_tmpListKeyLeafPath.m_location, parserContext.m_tmpListKeyLeafPath.m_node);
176 return parse_impl(actualType);
177 }
178 __builtin_unreachable();
179 };
180 auto pass = parse_impl(type);
181
182 if (!pass) {
183 if (parserContext.m_errorMsg.empty()) {
184 parserContext.m_errorMsg = "leaf data type mismatch: Expected " +
185 leafDataTypeToString(schema.leafType(parserContext.m_tmpListKeyLeafPath.m_location, parserContext.m_tmpListKeyLeafPath.m_node)) + " here:";
186 }
187 }
188 return pass;
189 }
190};
191
192auto const leaf_data = x3::no_skip[std::move(LeafData())];
193
Václav Kubernát9ae8cc42020-03-25 19:17:41 +0100194BOOST_SPIRIT_DEFINE(leaf_data_enum)
Václav Kubernát9ae8cc42020-03-25 19:17:41 +0100195BOOST_SPIRIT_DEFINE(leaf_data_string)
196BOOST_SPIRIT_DEFINE(leaf_data_binary_data)
197BOOST_SPIRIT_DEFINE(leaf_data_binary)
198BOOST_SPIRIT_DEFINE(leaf_data_identityRef_data)
199BOOST_SPIRIT_DEFINE(leaf_data_identityRef)
200BOOST_SPIRIT_DEFINE(createEnumSuggestions)
201BOOST_SPIRIT_DEFINE(createIdentitySuggestions)