Implement YangSchema subclass

While we do not necessarily want to use `-isystem` for libyang, we
definitely need to use it for Boost itself. We are only using SPirit X3
directly, but that one still brings in a great deal of other supporting
libraries, including variant and a metaprogramming library.

In our CI environment, these are installed into the same prefix. Boost
itself is OK as we're including it via cmake imported target which uses
-isystem behind the scene. However, if we then add libyang via a regular
target_include_directories, the same path gets pushed into the include
paths, this time without -isystem, but rather as a regular -I. This in
turn starts affecting Boost, and we're screwed.

Fix this by ensuring that we consider libyang to be a system library,
too. We won't get annoyed by some extra warnings and therefore we won't
be able to improve that library as much as the CI would force us
otherwise :).

Change-Id: I7ec9b28501a46f8b2219f4920cbf5c1e4df59d7e
diff --git a/src/yang_schema.hpp b/src/yang_schema.hpp
new file mode 100644
index 0000000..e30c701
--- /dev/null
+++ b/src/yang_schema.hpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2018 CESNET, https://photonics.cesnet.cz/
+ * Copyright (C) 2018 FIT CVUT, https://fit.cvut.cz/
+ *
+ * Written by Václav Kubernát <kubervac@fit.cvut.cz>
+ *
+*/
+
+#pragma once
+
+#include <set>
+#include <stdexcept>
+#include <unordered_map>
+#include "ast_path.hpp"
+#include "schema.hpp"
+
+class Context;
+class Set;
+class Schema_Node;
+
+/*! \class YangSchema
+ *     \brief A schema class, which uses libyang for queries.
+ *         */
+class YangSchema : public Schema {
+public:
+    YangSchema();
+    ~YangSchema() override;
+
+    bool isContainer(const path_& location, const ModuleNodePair& node) const override;
+    bool isLeaf(const path_& location, const ModuleNodePair& node) const override;
+    bool isModule(const path_& location, const std::string& name) const override;
+    bool isList(const path_& location, const ModuleNodePair& node) const override;
+    bool isPresenceContainer(const path_& location, const ModuleNodePair& node) const override;
+    bool leafEnumHasValue(const path_& location, const ModuleNodePair& node, const std::string& value) const override;
+    bool listHasKey(const path_& location, const ModuleNodePair& node, const std::string& key) const override;
+    bool nodeExists(const std::string& location, const std::string& node) const override;
+    const std::set<std::string> listKeys(const path_& location, const ModuleNodePair& node) const override;
+    yang::LeafDataTypes leafType(const path_& location, const ModuleNodePair& node) const override;
+    std::set<std::string> childNodes(const path_& path) const override;
+
+    /** @short Adds a new module passed as a YANG string. */
+    void addSchemaString(const char* schema);
+
+    /** @short Adds a new module from a file. */
+    void addSchemaFile(const char* filename);
+
+    /** @short Adds a new directory for schema lookup. */
+    void addSchemaDirectory(const char* directoryName);
+
+private:
+    std::set<std::string> modules() const;
+    bool nodeExists(const path_& location, const ModuleNodePair& node) const;
+
+    /** @short Returns a set of nodes, that match the location and name criteria. */
+    std::shared_ptr<Set> getNodeSet(const path_& location, const ModuleNodePair& node) const;
+
+    /** @short Returns a single Schema_Node if the criteria matches only one, otherwise nullptr. */
+    std::shared_ptr<Schema_Node> getSchemaNode(const path_& location, const ModuleNodePair& node) const;
+    std::shared_ptr<Context> m_context;
+};