Add support for yang type descriptions

Change-Id: I1fd070fb975aa82b2d4c1aa4165c5ab0153ff49f
diff --git a/src/interpreter.cpp b/src/interpreter.cpp
index f1682bf..aaa0595 100644
--- a/src/interpreter.cpp
+++ b/src/interpreter.cpp
@@ -127,6 +127,7 @@
 std::string Interpreter::buildTypeInfo(const std::string& path) const
 {
     std::ostringstream ss;
+    std::string typeDescription;
     switch (m_datastore.schema()->nodeType(path)) {
     case yang::NodeTypes::Container:
         ss << "container";
@@ -156,6 +157,10 @@
             ss << " [" + *leafType.m_units + "]";
         }
 
+        if (leafType.m_description) {
+            typeDescription = "\nType description: " + *leafType.m_description;
+        }
+
         if (m_datastore.schema()->leafIsKey(path)) {
             ss << " (key)";
         }
@@ -184,24 +189,29 @@
     }
 
     if (!m_datastore.schema()->isConfig(path)) {
-        ss << " (ro)";
+        ss << " (ro)\n";
     }
 
-    return ss.str();
-}
-
-void Interpreter::operator()(const describe_& describe) const
-{
-    auto path = pathToString(toCanonicalPath(describe.m_path));
     auto status = m_datastore.schema()->status(path);
     auto statusStr = status == yang::Status::Deprecated ? " (deprecated)" :
         status == yang::Status::Obsolete ? " (obsolete)" :
         "";
 
-    std::cout << path << ": " << buildTypeInfo(path) << statusStr << std::endl;
+    ss << statusStr;
+
     if (auto description = m_datastore.schema()->description(path)) {
-        std::cout << std::endl << *description << std::endl;
+        ss << std::endl << *description << std::endl;
     }
+
+    ss << typeDescription;
+    return ss.str();
+}
+
+void Interpreter::operator()(const describe_& describe) const
+{
+    auto fullPath = pathToString(toCanonicalPath(describe.m_path));
+
+    std::cout << pathToString(describe.m_path) << ": " << buildTypeInfo(fullPath) << std::endl;
 }
 
 void Interpreter::operator()(const move_& move) const
diff --git a/src/leaf_data_type.cpp b/src/leaf_data_type.cpp
index fe6fe04..f97e382 100644
--- a/src/leaf_data_type.cpp
+++ b/src/leaf_data_type.cpp
@@ -10,11 +10,12 @@
 namespace yang {
 bool TypeInfo::operator==(const TypeInfo& other) const
 {
-    return this->m_type == other.m_type && this->m_units == other.m_units;
+    return std::tie(this->m_type, this->m_units, this->m_description) == std::tie(other.m_type, other.m_units, other.m_description);
 }
-TypeInfo::TypeInfo(const yang::LeafDataType& type, const std::optional<std::string> units)
+TypeInfo::TypeInfo(const yang::LeafDataType& type, const std::optional<std::string> units, const std::optional<std::string> description)
     : m_type(type)
     , m_units(units)
+    , m_description(description)
 {
 }
 Enum::Enum(std::set<enum_>&& values)
diff --git a/src/leaf_data_type.hpp b/src/leaf_data_type.hpp
index 98cb12e..35a2961 100644
--- a/src/leaf_data_type.hpp
+++ b/src/leaf_data_type.hpp
@@ -105,9 +105,12 @@
     std::vector<TypeInfo> m_unionTypes;
 };
 struct TypeInfo {
-    TypeInfo(const yang::LeafDataType& type, const std::optional<std::string> units = std::nullopt);
+    TypeInfo(const yang::LeafDataType& type,
+            const std::optional<std::string> units = std::nullopt,
+            const std::optional<std::string> description = std::nullopt);
     bool operator==(const TypeInfo& other) const;
     yang::LeafDataType m_type;
     std::optional<std::string> m_units;
+    std::optional<std::string> m_description;
 };
 }
diff --git a/src/yang_schema.cpp b/src/yang_schema.cpp
index 7f27711..7e5bb9f 100644
--- a/src/yang_schema.cpp
+++ b/src/yang_schema.cpp
@@ -284,7 +284,19 @@
             }
         }
 
-        return yang::TypeInfo(resType, resUnits);
+        std::optional<std::string> resDescription;
+
+        // checking for parentTypedef->type()->der() means I'm going to enter inside base types like "string". These
+        // also have a description, but it isn't too helpful ("human-readable string")
+        for (auto parentTypedef = type->der(); parentTypedef && parentTypedef->type()->der(); parentTypedef = parentTypedef->type()->der()) {
+            auto dsc = parentTypedef->dsc();
+            if (dsc) {
+                resDescription = dsc;
+                break;
+            }
+        }
+
+        return yang::TypeInfo(resType, resUnits, resDescription);
     };
     return resolveType(leaf->type());
 }