Rework ParserContext temporary list context path
This context path is used mainly for parsing list suffixes. The
implementation is kind of wonky, as list suffixes were implemented with
the old style of parsing paths, but it still worked even with the new
path parser. However, I want to implement the upcoming `move` command, I
need to parse suffixes outside the path parser. This means I need to
fill in this list context path before I parse these suffixes. The
problem was that this context path was designed so that it is easy to
fill in inside the path parser, but right now I want to use it outside
of it. Filling it in outside the path parser meant doing manual stuff to
the context path and... well, it was difficult.
The way it was done before this patch only really made sense with the
old style parsing, so one could also see this patch as eliminating
remnants of the old code. Also, this patch removes the need for
ParserContext::m_curModule, because it was only used in list suffix
parsing.
This change adds new overloads to the Schema class, obsoleting some
other ones. Right now, I want to implement the new feature, and I'm
going to be deleted unused/obsolete overloads in another patch.
Change-Id: I6264d8b4215fcbe12f79a089f199d53ebe86edbf
diff --git a/src/ast_handlers.cpp b/src/ast_handlers.cpp
index 24866b2..f160d8c 100644
--- a/src/ast_handlers.cpp
+++ b/src/ast_handlers.cpp
@@ -23,3 +23,8 @@
}
return leafDataToString(value);
}
+
+boost::optional<std::string> optModuleToOptString(const boost::optional<module_> module)
+{
+ return module.flat_map([] (const auto& module) { return boost::optional<std::string>(module.m_name); });
+}
diff --git a/src/ast_handlers.hpp b/src/ast_handlers.hpp
index f378c18..b9d7a9d 100644
--- a/src/ast_handlers.hpp
+++ b/src/ast_handlers.hpp
@@ -46,24 +46,21 @@
struct node_identifier_class;
+boost::optional<std::string> optModuleToOptString(const boost::optional<module_> module);
+
struct key_identifier_class {
template <typename T, typename Iterator, typename Context>
void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
{
- auto& parserContext = x3::get<parser_context_tag>(context);
+ ParserContext& parserContext = x3::get<parser_context_tag>(context);
const Schema& schema = parserContext.m_schema;
- schemaPath_ location = parserContext.currentSchemaPath();
- ModuleNodePair list{parserContext.m_curModule, parserContext.m_tmpListName};
- if (schema.listHasKey(location, list, ast)) {
- schemaNode_ listNode;
- listNode.m_prefix = parserContext.m_curModule.flat_map([] (auto mod) { return boost::optional<module_>{{mod}}; });;
- listNode.m_suffix = list_{parserContext.m_tmpListName};
- location.m_nodes.push_back(listNode);
- parserContext.m_tmpListKeyLeafPath.m_location = location;
- parserContext.m_tmpListKeyLeafPath.m_node = { parserContext.m_curModule, ast };
+ if (schema.listHasKey(dataPathToSchemaPath(parserContext.m_tmpListPath), ast)) {
+ parserContext.m_tmpListKeyLeafPath.m_location = dataPathToSchemaPath(parserContext.m_tmpListPath);
+ parserContext.m_tmpListKeyLeafPath.m_node = { optModuleToOptString(parserContext.m_tmpListPath.m_nodes.back().m_prefix), ast };
} else {
- parserContext.m_errorMsg = parserContext.m_tmpListName + " is not indexed by \"" + ast + "\".";
+ auto listName = std::get<list_>(parserContext.m_tmpListPath.m_nodes.back().m_suffix).m_name;
+ parserContext.m_errorMsg = listName + " is not indexed by \"" + ast + "\".";
_pass(context) = false;
}
}
@@ -78,13 +75,14 @@
auto& parserContext = x3::get<parser_context_tag>(context);
const Schema& schema = parserContext.m_schema;
- const auto& keysNeeded = schema.listKeys(parserContext.currentSchemaPath(), {parserContext.m_curModule, parserContext.m_tmpListName});
+ const auto& keysNeeded = schema.listKeys(dataPathToSchemaPath(parserContext.m_tmpListPath));
std::set<std::string> keysSupplied;
for (const auto& it : ast)
keysSupplied.insert(it.first);
if (keysNeeded != keysSupplied) {
- parserContext.m_errorMsg = "Not enough keys for " + parserContext.m_tmpListName + ". " +
+ auto listName = std::get<list_>(parserContext.m_tmpListPath.m_nodes.back().m_suffix).m_name;
+ parserContext.m_errorMsg = "Not enough keys for " + listName + ". " +
"These keys were not supplied:";
std::set<std::string> missingKeys;
std::set_difference(keysNeeded.begin(), keysNeeded.end(),
@@ -302,7 +300,6 @@
auto& parserContext = x3::get<parser_context_tag>(context);
parserContext.resetPath();
parserContext.m_tmpListKeys.clear();
- parserContext.m_tmpListName.clear();
parserContext.m_suggestions.clear();
}
};
@@ -320,7 +317,7 @@
parserContext.m_completionIterator = begin;
- const auto& keysNeeded = schema.listKeys(parserContext.currentSchemaPath(), {parserContext.m_curModule, parserContext.m_tmpListName});
+ const auto& keysNeeded = schema.listKeys(dataPathToSchemaPath(parserContext.m_tmpListPath));
parserContext.m_suggestions = generateMissingKeyCompletionSet(keysNeeded, parserContext.m_tmpListKeys);
}
};
@@ -338,7 +335,7 @@
const auto& dataQuery = parserContext.m_dataquery;
parserContext.m_completionIterator = begin;
- auto listInstances = dataQuery->listKeys(parserContext.currentDataPath(), {parserContext.m_curModule, parserContext.m_tmpListName});
+ auto listInstances = dataQuery->listKeys(parserContext.m_tmpListPath);
decltype(listInstances) filteredInstances;
//This filters out instances, which don't correspond to the partial instance we have.
@@ -369,7 +366,7 @@
const auto& schema = parserContext.m_schema;
parserContext.m_completionIterator = begin;
- const auto& keysNeeded = schema.listKeys(parserContext.currentSchemaPath(), {parserContext.m_curModule, parserContext.m_tmpListName});
+ const auto& keysNeeded = schema.listKeys(dataPathToSchemaPath(parserContext.m_tmpListPath));
if (generateMissingKeyCompletionSet(keysNeeded, parserContext.m_tmpListKeys).empty()) {
parserContext.m_suggestions = {Completion{"]/"}};
} else {
diff --git a/src/ast_path.cpp b/src/ast_path.cpp
index 1a26a1c..f7c0022 100644
--- a/src/ast_path.cpp
+++ b/src/ast_path.cpp
@@ -61,6 +61,13 @@
{
}
+dataNode_::dataNode_(boost::optional<module_> module, decltype(m_suffix) node)
+ : m_prefix(module)
+ , m_suffix(node)
+{
+
+}
+
schemaNode_::schemaNode_(decltype(m_suffix) node)
: m_suffix(node)
{
diff --git a/src/ast_path.hpp b/src/ast_path.hpp
index b1b949c..cb84e80 100644
--- a/src/ast_path.hpp
+++ b/src/ast_path.hpp
@@ -97,6 +97,7 @@
dataNode_();
dataNode_(decltype(m_suffix) node);
+ dataNode_(boost::optional<module_> module, decltype(m_suffix) node);
dataNode_(module_ module, decltype(m_suffix) node);
bool operator==(const dataNode_& b) const;
};
diff --git a/src/data_query.cpp b/src/data_query.cpp
index be979ff..cef7ec3 100644
--- a/src/data_query.cpp
+++ b/src/data_query.cpp
@@ -10,9 +10,9 @@
m_schema = m_datastore.schema();
}
-std::vector<ListInstance> DataQuery::listKeys(const dataPath_& location, const ModuleNodePair& node) const
+std::vector<ListInstance> DataQuery::listKeys(const dataPath_& listPath) const
{
- auto listPath = joinPaths(pathToDataString(location, Prefixes::Always), fullNodeName(location, node));
+ auto listPathString = pathToDataString(listPath, Prefixes::Always);
- return m_datastore.listInstances(listPath);
+ return m_datastore.listInstances(listPathString);
}
diff --git a/src/data_query.hpp b/src/data_query.hpp
index b2f4a33..7a54a33 100644
--- a/src/data_query.hpp
+++ b/src/data_query.hpp
@@ -24,11 +24,10 @@
public:
DataQuery(DatastoreAccess& datastore);
/*! \brief Lists all possible instances of key/value pairs for a list specified by the arguments.
- * \param location Location of the list.
- * \param node Name (and optional module name) of the list.
+ * \param listPath Path to the list (ending with a list_)
* \return A vector of maps, which represent the instances. The map is keyed by the name of the list key. The values in the map, are values of the list keys.
*/
- std::vector<ListInstance> listKeys(const dataPath_& location, const ModuleNodePair& node) const;
+ std::vector<ListInstance> listKeys(const dataPath_& listPath) const;
private:
DatastoreAccess& m_datastore;
diff --git a/src/parser_context.hpp b/src/parser_context.hpp
index 9ef9d80..88dc71a 100644
--- a/src/parser_context.hpp
+++ b/src/parser_context.hpp
@@ -23,16 +23,17 @@
const Schema& m_schema;
const dataPath_ m_curPathOrig;
const std::shared_ptr<const DataQuery> m_dataquery;
- boost::optional<std::string> m_curModule;
std::string m_errorMsg;
- std::string m_tmpListName;
struct {
schemaPath_ m_location;
ModuleNodePair m_node;
} m_tmpListKeyLeafPath;
+ // When parsing list suffixes, this path is used to store the path of the list whose keys are being parsed.
+ dataPath_ m_tmpListPath;
std::map<std::string, leaf_data_> m_tmpListKeys;
+
bool m_errorHandled = false;
bool m_completing = false;
diff --git a/src/path_parser.hpp b/src/path_parser.hpp
index b978d71..6d9a304 100644
--- a/src/path_parser.hpp
+++ b/src/path_parser.hpp
@@ -166,10 +166,6 @@
auto res = table.parse(begin, end, ctx, rctx, attr);
- if (attr.m_prefix) {
- parserContext.m_curModule = attr.m_prefix->m_name;
- }
-
if (std::holds_alternative<leaf_>(attr.m_suffix)) {
parserContext.m_tmpListKeyLeafPath.m_location = parserContext.currentSchemaPath();
ModuleNodePair node{attr.m_prefix.flat_map([](const auto& it) {
@@ -181,7 +177,10 @@
if constexpr (std::is_same<attribute_type, dataNode_>()) {
if (std::holds_alternative<listElement_>(attr.m_suffix)) {
- parserContext.m_tmpListName = std::get<listElement_>(attr.m_suffix).m_name;
+ parserContext.m_tmpListPath = parserContext.currentDataPath();
+ auto tmpList = list_{std::get<listElement_>(attr.m_suffix).m_name};
+ parserContext.m_tmpListPath.m_nodes.push_back(dataNode_{attr.m_prefix, tmpList});
+
res = listSuffix.parse(begin, end, ctx, rctx, std::get<listElement_>(attr.m_suffix).m_keys);
// FIXME: think of a better way to do this, that is, get rid of manual iterator reverting
@@ -221,9 +220,6 @@
parserContext.pushPathFragment(attr);
}
- if (attr.m_prefix) {
- parserContext.m_curModule = boost::none;
- }
return res;
}
}
diff --git a/src/schema.hpp b/src/schema.hpp
index 995d921..42d0728 100644
--- a/src/schema.hpp
+++ b/src/schema.hpp
@@ -63,10 +63,12 @@
virtual yang::NodeTypes nodeType(const schemaPath_& location, const ModuleNodePair& node) const = 0;
virtual bool isModule(const std::string& name) const = 0;
virtual bool listHasKey(const schemaPath_& location, const ModuleNodePair& node, const std::string& key) const = 0;
+ virtual bool listHasKey(const schemaPath_& listPath, const std::string& key) const = 0;
virtual bool leafIsKey(const std::string& leafPath) const = 0;
virtual bool isConfig(const std::string& path) const = 0;
virtual std::optional<std::string> defaultValue(const std::string& leafPath) const = 0;
virtual const std::set<std::string> listKeys(const schemaPath_& location, const ModuleNodePair& node) const = 0;
+ virtual const std::set<std::string> listKeys(const schemaPath_& listPath) const = 0;
virtual yang::TypeInfo leafType(const schemaPath_& location, const ModuleNodePair& node) const = 0;
virtual yang::TypeInfo leafType(const std::string& path) const = 0;
virtual std::optional<std::string> leafTypeName(const std::string& path) const = 0;
diff --git a/src/static_schema.cpp b/src/static_schema.cpp
index 5fdc42a..203b61e 100644
--- a/src/static_schema.cpp
+++ b/src/static_schema.cpp
@@ -44,6 +44,11 @@
return list.m_keys.find(key) != list.m_keys.end();
}
+bool StaticSchema::listHasKey(const schemaPath_& listPath, const std::string& key) const
+{
+ return listKeys(listPath).count(key);
+}
+
const std::set<std::string> StaticSchema::listKeys(const schemaPath_& location, const ModuleNodePair& node) const
{
std::string locationString = pathToSchemaString(location, Prefixes::Always);
@@ -54,6 +59,23 @@
return list.m_keys;
}
+std::string lastNodeOfSchemaPath(const std::string& path)
+{
+ std::string res = path;
+ if (auto pos = res.find_last_of('/'); pos != res.npos) {
+ res.erase(0, pos + 1);
+ }
+ return res;
+}
+
+const std::set<std::string> StaticSchema::listKeys(const schemaPath_& listPath) const
+{
+ auto listPathString = pathToSchemaString(listPath, Prefixes::Always);
+ const auto& child = children(stripLastNodeFromPath(listPathString)).at(lastNodeOfSchemaPath(listPathString));
+ const auto& list = std::get<yang::list>(child.m_nodeType);
+ return list.m_keys;
+}
+
void StaticSchema::addList(const std::string& location, const std::string& name, const std::set<std::string>& keys)
{
m_nodes.at(location).emplace(name, NodeInfo{yang::list{keys}, yang::AccessType::Writable});
@@ -106,15 +128,6 @@
}
}
-std::string lastNodeOfSchemaPath(const std::string& path)
-{
- std::string res = path;
- if (auto pos = res.find_last_of('/'); pos != res.npos) {
- res.erase(0, pos + 1);
- }
- return res;
-}
-
yang::TypeInfo StaticSchema::leafType(const schemaPath_& location, const ModuleNodePair& node) const
{
std::string locationString = pathToSchemaString(location, Prefixes::Always);
diff --git a/src/static_schema.hpp b/src/static_schema.hpp
index 0426f02..09b6271 100644
--- a/src/static_schema.hpp
+++ b/src/static_schema.hpp
@@ -63,10 +63,12 @@
yang::NodeTypes nodeType(const schemaPath_& location, const ModuleNodePair& node) const override;
bool isModule(const std::string& name) const override;
bool listHasKey(const schemaPath_& location, const ModuleNodePair& node, const std::string& key) const override;
+ bool listHasKey(const schemaPath_& listPath, const std::string& key) const override;
bool leafIsKey(const std::string& leafPath) const override;
bool isConfig(const std::string& leafPath) const override;
std::optional<std::string> defaultValue(const std::string& leafPath) const override;
const std::set<std::string> listKeys(const schemaPath_& location, const ModuleNodePair& node) const override;
+ const std::set<std::string> listKeys(const schemaPath_& listPath) const override;
yang::TypeInfo leafType(const schemaPath_& location, const ModuleNodePair& node) const override;
yang::TypeInfo leafType(const std::string& path) const override;
std::optional<std::string> leafTypeName(const std::string& path) const override;
diff --git a/src/yang_schema.cpp b/src/yang_schema.cpp
index 48b3724..b44ef5f 100644
--- a/src/yang_schema.cpp
+++ b/src/yang_schema.cpp
@@ -101,6 +101,12 @@
return keys.find(key) != keys.end();
}
+bool YangSchema::listHasKey(const schemaPath_& listPath, const std::string& key) const
+{
+ const auto keys = listKeys(listPath);
+ return keys.find(key) != keys.end();
+}
+
bool YangSchema::leafIsKey(const std::string& leafPath) const
{
auto node = getSchemaNode(leafPath);
@@ -141,17 +147,36 @@
return impl_getSchemaNode(absPath);
}
-const std::set<std::string> YangSchema::listKeys(const schemaPath_& location, const ModuleNodePair& node) const
+libyang::S_Schema_Node YangSchema::getSchemaNode(const schemaPath_& listPath) const
+{
+ std::string absPath = pathToSchemaString(listPath, Prefixes::Always);
+ return impl_getSchemaNode(absPath);
+}
+
+namespace {
+const std::set<std::string> impl_listKeys(const libyang::S_Schema_Node_List& list)
{
std::set<std::string> keys;
- if (!isList(location, node))
- return keys;
- libyang::Schema_Node_List list(getSchemaNode(location, node));
- const auto& keysVec = list.keys();
+ const auto& keysVec = list->keys();
std::transform(keysVec.begin(), keysVec.end(), std::inserter(keys, keys.begin()), [](const auto& it) { return it->name(); });
return keys;
}
+}
+
+const std::set<std::string> YangSchema::listKeys(const schemaPath_& location, const ModuleNodePair& node) const
+{
+ if (!isList(location, node))
+ return {};
+ auto list = std::make_shared<libyang::Schema_Node_List>(getSchemaNode(location, node));
+ return impl_listKeys(list);
+}
+
+const std::set<std::string> YangSchema::listKeys(const schemaPath_& listPath) const
+{
+ auto list = std::make_shared<libyang::Schema_Node_List>(getSchemaNode(listPath));
+ return impl_listKeys(list);
+}
namespace {
std::set<enum_> enumValues(const libyang::S_Type& typeArg)
diff --git a/src/yang_schema.hpp b/src/yang_schema.hpp
index 5b2db04..aed1a5d 100644
--- a/src/yang_schema.hpp
+++ b/src/yang_schema.hpp
@@ -35,10 +35,12 @@
yang::NodeTypes nodeType(const schemaPath_& location, const ModuleNodePair& node) const override;
bool isModule(const std::string& name) const override;
bool listHasKey(const schemaPath_& location, const ModuleNodePair& node, const std::string& key) const override;
+ bool listHasKey(const schemaPath_& listPath, const std::string& key) const override;
bool leafIsKey(const std::string& leafPath) const override;
bool isConfig(const std::string& path) const override;
std::optional<std::string> defaultValue(const std::string& leafPath) const override;
const std::set<std::string> listKeys(const schemaPath_& location, const ModuleNodePair& node) const override;
+ const std::set<std::string> listKeys(const schemaPath_& listPath) const override;
yang::TypeInfo leafType(const schemaPath_& location, const ModuleNodePair& node) const override;
yang::TypeInfo leafType(const std::string& path) const override;
/** @brief If the leaf type is a typedef, returns the typedef name. */
@@ -74,10 +76,11 @@
yang::TypeInfo impl_leafType(const std::shared_ptr<libyang::Schema_Node>& node) const;
std::set<std::string> modules() const;
- /** @short Returns a set of nodes, that match the location and name criteria. */
/** @short Returns a single Schema_Node if the criteria matches only one, otherwise nullptr. */
std::shared_ptr<libyang::Schema_Node> getSchemaNode(const std::string& node) const;
+ /** @short Returns a single Schema_Node if the criteria matches only one, otherwise nullptr. */
+ std::shared_ptr<libyang::Schema_Node> getSchemaNode(const schemaPath_& listPath) const;
/** @short Returns a single Schema_Node if the criteria matches only one, otherwise nullptr. */
std::shared_ptr<libyang::Schema_Node> getSchemaNode(const schemaPath_& location, const ModuleNodePair& node) const;