yin parser FEATURE in YANG 1.1 support enumeration and bits restrictions

Allow restriction on derived types from some other enumeration/bits based
type.
diff --git a/src/common.h b/src/common.h
index 72f34dc..a41f78a 100644
--- a/src/common.h
+++ b/src/common.h
@@ -149,9 +149,13 @@
     LYE_DUPLEAFLIST,
     LYE_DUPLIST,
     LYE_NOUNIQ,
+    LYE_ENUM_INVAL,
+    LYE_ENUM_INNAME,
     LYE_ENUM_DUPVAL,
     LYE_ENUM_DUPNAME,
     LYE_ENUM_WS,
+    LYE_BITS_INVAL,
+    LYE_BITS_INNAME,
     LYE_BITS_DUPVAL,
     LYE_BITS_DUPNAME,
     LYE_INMOD,
diff --git a/src/libyang.h b/src/libyang.h
index d915b9d..cf22c4d 100644
--- a/src/libyang.h
+++ b/src/libyang.h
@@ -1169,11 +1169,15 @@
     LYVE_DUPLEAFLIST,  /**< multiple instances of leaf-list */
     LYVE_DUPLIST,      /**< multiple instances of list */
     LYVE_NOUNIQ,       /**< unique leaves match on 2 list instances (data) */
-    LYVE_ENUM_DUPVAL,  /**< duplicated enum value (schema) */
-    LYVE_ENUM_DUPNAME, /**< duplicated enum name (schema) */
+    LYVE_ENUM_INVAL,   /**< invalid enum value (schema) */
+    LYVE_ENUM_INNAME,  /**< invalid enum name (schema) */
+    /* */
+    /* */
     LYVE_ENUM_WS,      /**< enum name with leading/trailing whitespaces (schema) */
-    LYVE_BITS_DUPVAL,  /**< duplicated bits value (schema) */
-    LYVE_BITS_DUPNAME, /**< duplicated bits name (schema) */
+    LYVE_BITS_INVAL,   /**< invalid bits value (schema) */
+    LYVE_BITS_INNAME,  /**< invalid bits name (schema) */
+    /* */
+    /* */
     LYVE_INMOD,        /**< invalid module name */
     /* */
     LYVE_KEY_NLEAF,    /**< list key is not a leaf (schema) */
diff --git a/src/log.c b/src/log.c
index a8626e8..81bb922 100644
--- a/src/log.c
+++ b/src/log.c
@@ -146,10 +146,14 @@
 /* LYE_DUPLEAFLIST */  "Duplicated instance of \"%s\" leaf-list (\"%s\").",
 /* LYE_DUPLIST */      "Duplicated instance of \"%s\" list.",
 /* LYE_NOUNIQ */       "Unique data leaf(s) \"%s\" not satisfied in \"%s\" and \"%s\".",
-/* LYE_ENUM_DUPVAL */  "The value \"%d\" of \"%s\" enum has already been assigned to another enum value.",
+/* LYE_ENUM_INVAL */   "Invalid value \"%d\" of \"%s\" enum - restricted enum value does not match the base type value.",
+/* LYE_ENUM_INNAME */  "Invalid enum name \"%s\" - restricted enum must use only base type enum names.",
+/* LYE_ENUM_DUPVAL */  "The value \"%d\" of \"%s\" enum has already been assigned to \"%s\" enum.",
 /* LYE_ENUM_DUPNAME */ "The enum name \"%s\" has already been assigned to another enum.",
 /* LYE_ENUM_WS */      "The enum name \"%s\" includes invalid leading or trailing whitespaces.",
-/* LYE_BITS_DUPVAL */  "The position \"%d\" of \"%s\" bits has already been used to another named bit.",
+/* LYE_BITS_INVAL */   "Invalid position \"%d\" of \"%s\" bit - restricted bits position does not match the base type position.",
+/* LYE_BITS_INNAME */  "Invalid bit name \"%s\" - restricted bits must use only base type bits names.",
+/* LYE_BITS_DUPVAL */  "The position \"%d\" of \"%s\" bit has already been assigned to \"%s\" bit.",
 /* LYE_BITS_DUPNAME */ "The bit name \"%s\" has already been assigned to another bit.",
 /* LYE_INMOD */        "Module name \"%s\" refers to an unknown module.",
 /* LYE_INMOD_LEN */    "Module name \"%.*s\" refers to an unknown module.",
@@ -233,11 +237,15 @@
     LYVE_DUPLEAFLIST,  /* LYE_DUPLEAFLIST */
     LYVE_DUPLIST,      /* LYE_DUPLIST */
     LYVE_NOUNIQ,       /* LYE_NOUNIQ */
-    LYVE_ENUM_DUPVAL,  /* LYE_ENUM_DUPVAL */
-    LYVE_ENUM_DUPNAME, /* LYE_ENUM_DUPNAME */
+    LYVE_ENUM_INVAL,   /* LYE_ENUM_INVAL */
+    LYVE_ENUM_INNAME,  /* LYE_ENUM_INNAME */
+    LYVE_ENUM_INVAL,   /* LYE_ENUM_DUPVAL */
+    LYVE_ENUM_INNAME,  /* LYE_ENUM_DUPNAME */
     LYVE_ENUM_WS,      /* LYE_ENUM_WS */
-    LYVE_BITS_DUPVAL,  /* LYE_BITS_DUPVAL */
-    LYVE_BITS_DUPNAME, /* LYE_BITS_DUPNAME */
+    LYVE_BITS_INVAL,   /* LYE_BITS_INVAL */
+    LYVE_BITS_INNAME,  /* LYE_BITS_INNAME */
+    LYVE_BITS_INVAL,   /* LYE_BITS_DUPVAL */
+    LYVE_BITS_INNAME,  /* LYE_BITS_DUPNAME */
     LYVE_INMOD,        /* LYE_INMOD */
     LYVE_INMOD,        /* LYE_INMOD_LEN */
     LYVE_KEY_NLEAF,    /* LYE_KEY_NLEAF */
diff --git a/src/parser.c b/src/parser.c
index 8a9e819..1647b18 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -869,8 +869,10 @@
         break;
 
     case LY_TYPE_BITS:
-        /* locate bits structure with the bits definitions */
-        for (type = stype; type->der->type.der; type = &type->der->type);
+        /* locate bits structure with the bits definitions
+         * since YANG 1.1 allows restricted bits, it is the first
+         * bits type with some explicit bit specification */
+        for (type = stype; !type->info.bits.count; type = &type->der->type);
 
         /* allocate the array of  pointers to bits definition */
         node->value.bit = calloc(type->info.bits.count, sizeof *node->value.bit);
@@ -1025,8 +1027,10 @@
             return EXIT_FAILURE;
         }
 
-        /* locate enums structure with the enumeration definitions */
-        for (type = stype; type->der->type.der; type = &type->der->type);
+        /* locate enums structure with the enumeration definitions,
+         * since YANG 1.1 allows restricted enums, it is the first
+         * enum type with some explicit enum specification */
+        for (type = stype; !type->info.enums.count; type = &type->der->type);
 
         /* find matching enumeration value */
         for (i = 0; i < type->info.enums.count; i++) {
diff --git a/src/parser_yang.c b/src/parser_yang.c
index 5008d38..3dc30e9 100644
--- a/src/parser_yang.c
+++ b/src/parser_yang.c
@@ -1279,7 +1279,8 @@
     for (i = 0; i < j; i++) {
         if (typ->type->info.enums.enm[i].value == typ->type->info.enums.enm[j].value) {
             LOGVAL(LYE_ENUM_DUPVAL, LY_VLOG_NONE, NULL,
-                   typ->type->info.enums.enm[j].value, typ->type->info.enums.enm[j].name);
+                   typ->type->info.enums.enm[j].value, typ->type->info.enums.enm[j].name,
+                   typ->type->info.enums.enm[i].name);
             goto error;
         }
     }
@@ -1339,7 +1340,7 @@
     /* check that the value is unique */
     for (i = 0; i < j; i++) {
         if (typ->type->info.bits.bit[i].pos == bit->pos) {
-            LOGVAL(LYE_BITS_DUPVAL, LY_VLOG_NONE, NULL, bit->pos, bit->name);
+            LOGVAL(LYE_BITS_DUPVAL, LY_VLOG_NONE, NULL, bit->pos, bit->name, typ->type->info.bits.bit[i].name);
             goto error;
         }
     }
diff --git a/src/parser_yin.c b/src/parser_yin.c
index 98ee822..73592b8 100644
--- a/src/parser_yin.c
+++ b/src/parser_yin.c
@@ -241,7 +241,9 @@
     struct lys_node *siter;
     struct lyxml_elem *next, *node;
     struct lys_restr **restr;
-    struct lys_type_bit bit;
+    struct lys_type_bit bit, *bits_sc;
+    struct lys_type_enum *enms_sc; /* shortcut */
+    struct lys_type *dertype;
     int i, j, rc, val_set;
     int ret = -1;
     int64_t v, v_;
@@ -314,15 +316,21 @@
                 goto error;
             }
         }
-        if (!type->der->type.der && !type->info.bits.count) {
-            /* type is derived directly from buit-in bits type and bit statement is required */
-            LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "bit", "type");
-            goto error;
-        }
-        if (type->der->type.der && type->info.bits.count) {
-            /* type is not directly derived from buit-in bits type and bit statement is prohibited */
-            LOGVAL(LYE_INSTMT, LY_VLOG_NONE, NULL, "bit");
-            goto error;
+        dertype = &type->der->type;
+        if (!dertype->der) {
+            if (!type->info.bits.count) {
+                /* type is derived directly from buit-in bits type and bit statement is required */
+                LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "bit", "type");
+                goto error;
+            }
+        } else {
+            for (; !dertype->info.enums.count; dertype = &dertype->der->type);
+            if (module->version < 2 && type->info.bits.count) {
+                /* type is not directly derived from buit-in bits type and bit statement is prohibited,
+                 * since YANG 1.1 the bit statements can be used to restrict the base bits type */
+                LOGVAL(LYE_INSTMT, LY_VLOG_NONE, NULL, "bit");
+                goto error;
+            }
         }
 
         type->info.bits.bit = calloc(type->info.bits.count, sizeof *type->info.bits.bit);
@@ -346,15 +354,31 @@
                 goto error;
             }
 
-            /* check the name uniqueness */
-            for (j = 0; j < i; j++) {
-                if (!strcmp(type->info.bits.bit[j].name, type->info.bits.bit[i].name)) {
-                    LOGVAL(LYE_BITS_DUPNAME, LY_VLOG_NONE, NULL, type->info.bits.bit[i].name);
+            if (!dertype->der) { /* directly derived type from bits built-in type */
+                /* check the name uniqueness */
+                for (j = 0; j < i; j++) {
+                    if (!strcmp(type->info.bits.bit[j].name, type->info.bits.bit[i].name)) {
+                        LOGVAL(LYE_BITS_DUPNAME, LY_VLOG_NONE, NULL, type->info.bits.bit[i].name);
+                        type->info.bits.count = i + 1;
+                        goto error;
+                    }
+                }
+            } else {
+                /* restricted bits type - the name MUST be used in the base type */
+                bits_sc = dertype->info.bits.bit;
+                for (j = 0; j < dertype->info.bits.count; j++) {
+                    if (ly_strequal(bits_sc[j].name, value, 1)) {
+                        break;
+                    }
+                }
+                if (j == dertype->info.bits.count) {
+                    LOGVAL(LYE_BITS_INNAME, LY_VLOG_NONE, NULL, value);
                     type->info.bits.count = i + 1;
                     goto error;
                 }
             }
 
+
             p_ = -1;
             LY_TREE_FOR(next->child, node) {
                 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
@@ -363,6 +387,12 @@
                 }
 
                 if (!strcmp(node->name, "position")) {
+                    if (p_ != -1) {
+                        LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, next->name);
+                        type->info.bits.count = i + 1;
+                        goto error;
+                    }
+
                     GETVAL(value, node, "value");
                     p_ = strtoll(value, NULL, 10);
 
@@ -374,18 +404,21 @@
                     }
                     type->info.bits.bit[i].pos = (uint32_t)p_;
 
-                    /* keep the highest enum value for automatic increment */
-                    if (type->info.bits.bit[i].pos >= p) {
-                        p = type->info.bits.bit[i].pos;
-                        p++;
-                    } else {
-                        /* check that the value is unique */
-                        for (j = 0; j < i; j++) {
-                            if (type->info.bits.bit[j].pos == type->info.bits.bit[i].pos) {
-                                LOGVAL(LYE_BITS_DUPVAL, LY_VLOG_NONE, NULL,
-                                       type->info.bits.bit[i].pos, type->info.bits.bit[i].name);
-                                type->info.bits.count = i + 1;
-                                goto error;
+                    if (!dertype->der) { /* directly derived type from bits built-in type */
+                        /* keep the highest enum value for automatic increment */
+                        if (type->info.bits.bit[i].pos >= p) {
+                            p = type->info.bits.bit[i].pos;
+                            p++;
+                        } else {
+                            /* check that the value is unique */
+                            for (j = 0; j < i; j++) {
+                                if (type->info.bits.bit[j].pos == type->info.bits.bit[i].pos) {
+                                    LOGVAL(LYE_BITS_DUPVAL, LY_VLOG_NONE, NULL,
+                                           type->info.bits.bit[i].pos, type->info.bits.bit[i].name,
+                                           type->info.bits.bit[j].name);
+                                    type->info.bits.count = i + 1;
+                                    goto error;
+                                }
                             }
                         }
                     }
@@ -394,16 +427,36 @@
                     goto error;
                 }
             }
-            if (p_ == -1) {
-                /* assign value automatically */
-                if (p > UINT32_MAX) {
-                    LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, "4294967295", "bit/position");
-                    type->info.bits.count = i + 1;
-                    goto error;
+
+            if (!dertype->der) { /* directly derived type from bits built-in type */
+                if (p_ == -1) {
+                    /* assign value automatically */
+                    if (p > UINT32_MAX) {
+                        LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, "4294967295", "bit/position");
+                        type->info.bits.count = i + 1;
+                        goto error;
+                    }
+                    type->info.bits.bit[i].pos = (uint32_t)p;
+                    type->info.bits.bit[i].flags |= LYS_AUTOASSIGNED;
+                    p++;
                 }
-                type->info.bits.bit[i].pos = (uint32_t)p;
-                type->info.bits.bit[i].flags |= LYS_AUTOASSIGNED;
-                p++;
+            } else { /* restricted bits type */
+                if (p_ == -1) {
+                    /* automatically assign position from base type */
+                    type->info.bits.bit[i].pos = bits_sc[j].pos;
+                    type->info.bits.bit[i].flags |= LYS_AUTOASSIGNED;
+                } else {
+                    /* check that the assigned position corresponds to the original
+                     * position of the bit in the base type */
+                    if (p_ != bits_sc[j].pos) {
+                        /* p_ - assigned position in restricted bits
+                         * bits_sc[j].pos - position assigned to the corresponding bit (detected above) in base type */
+                        LOGVAL(LYE_BITS_INVAL, LY_VLOG_NONE, NULL, type->info.bits.bit[i].pos,
+                               type->info.bits.bit[i].name);
+                        type->info.bits.count = i + 1;
+                        goto error;
+                    }
+                }
             }
 
             /* keep them ordered by position */
@@ -503,15 +556,21 @@
                 goto error;
             }
         }
-        if (!type->der->type.der && !type->info.enums.count) {
-            /* type is derived directly from buit-in enumeartion type and enum statement is required */
-            LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "enum", "type");
-            goto error;
-        }
-        if (type->der->type.der && type->info.enums.count) {
-            /* type is not directly derived from buit-in enumeration type and enum statement is prohibited */
-            LOGVAL(LYE_INSTMT, LY_VLOG_NONE, NULL, "enum");
-            goto error;
+        dertype = &type->der->type;
+        if (!dertype->der) {
+            if (!type->info.enums.count) {
+                /* type is derived directly from buit-in enumeartion type and enum statement is required */
+                LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "enum", "type");
+                goto error;
+            }
+        } else {
+            for (; !dertype->info.enums.count; dertype = &dertype->der->type);
+            if (module->version < 2 && type->info.enums.count) {
+                /* type is not directly derived from built-in enumeration type and enum statement is prohibited
+                 * in YANG 1.0, since YANG 1.1 enum statements can be used to restrict the base enumeration type */
+                LOGVAL(LYE_INSTMT, LY_VLOG_NONE, NULL, "enum");
+                goto error;
+            }
         }
 
         type->info.enums.enm = calloc(type->info.enums.count, sizeof *type->info.enums.enm);
@@ -520,7 +579,7 @@
             goto error;
         }
 
-        val_set = v = 0;
+        v = 0;
         i = -1;
         LY_TREE_FOR(yin->child, next) {
             i++;
@@ -545,15 +604,31 @@
                 goto error;
             }
 
-            /* check the name uniqueness */
-            for (j = 0; j < i; j++) {
-                if (!strcmp(type->info.enums.enm[j].name, type->info.enums.enm[i].name)) {
-                    LOGVAL(LYE_ENUM_DUPNAME, LY_VLOG_NONE, NULL, type->info.enums.enm[i].name);
+            if (!dertype->der) { /* directly derived type from enumeration built-in type */
+                /* check the name uniqueness */
+                for (j = 0; j < i; j++) {
+                    if (ly_strequal(type->info.enums.enm[j].name, value, 1)) {
+                        LOGVAL(LYE_ENUM_DUPNAME, LY_VLOG_NONE, NULL, value);
+                        type->info.enums.count = i + 1;
+                        goto error;
+                    }
+                }
+            } else {
+                /* restricted enumeration type - the name MUST be used in the base type */
+                enms_sc = dertype->info.enums.enm;
+                for (j = 0; j < dertype->info.enums.count; j++) {
+                    if (ly_strequal(enms_sc[j].name, value, 1)) {
+                        break;
+                    }
+                }
+                if (j == dertype->info.enums.count) {
+                    LOGVAL(LYE_ENUM_INNAME, LY_VLOG_NONE, NULL, value);
                     type->info.enums.count = i + 1;
                     goto error;
                 }
             }
 
+            val_set = 0;
             LY_TREE_FOR(next->child, node) {
                 if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
                     /* garbage */
@@ -561,6 +636,12 @@
                 }
 
                 if (!strcmp(node->name, "value")) {
+                    if (val_set) {
+                        LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, next->name);
+                        type->info.enums.count = i + 1;
+                        goto error;
+                    }
+
                     GETVAL(value, node, "value");
                     v_ = strtoll(value, NULL, 10);
 
@@ -572,18 +653,21 @@
                     }
                     type->info.enums.enm[i].value = v_;
 
-                    /* keep the highest enum value for automatic increment */
-                    if (!val_set || type->info.enums.enm[i].value > v) {
-                        v = type->info.enums.enm[i].value;
-                        v++;
-                    } else {
-                        /* check that the value is unique */
-                        for (j = 0; j < i; j++) {
-                            if (type->info.enums.enm[j].value == type->info.enums.enm[i].value) {
-                                LOGVAL(LYE_ENUM_DUPVAL, LY_VLOG_NONE, NULL,
-                                       type->info.enums.enm[i].value, type->info.enums.enm[i].name);
-                                type->info.enums.count = i + 1;
-                                goto error;
+                    if (!dertype->der) { /* directly derived type from enumeration built-in type */
+                        /* keep the highest enum value for automatic increment */
+                        if (type->info.enums.enm[i].value > v) {
+                            v = type->info.enums.enm[i].value;
+                            v++;
+                        } else {
+                            /* check that the value is unique */
+                            for (j = 0; j < i; j++) {
+                                if (type->info.enums.enm[j].value == type->info.enums.enm[i].value) {
+                                    LOGVAL(LYE_ENUM_DUPVAL, LY_VLOG_NONE, NULL,
+                                           type->info.enums.enm[i].value, type->info.enums.enm[i].name,
+                                           type->info.enums.enm[j].name);
+                                    type->info.enums.count = i + 1;
+                                    goto error;
+                                }
                             }
                         }
                     }
@@ -593,16 +677,36 @@
                     goto error;
                 }
             }
-            if (!val_set) {
-                /* assign value automatically */
-                if (v > INT32_MAX) {
-                    LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, "2147483648", "enum/value");
-                    type->info.enums.count = i + 1;
-                    goto error;
+
+            if (!dertype->der) { /* directly derived type from enumeration */
+                if (!val_set) {
+                    /* assign value automatically */
+                    if (v > INT32_MAX) {
+                        LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, "2147483648", "enum/value");
+                        type->info.enums.count = i + 1;
+                        goto error;
+                    }
+                    type->info.enums.enm[i].value = v;
+                    type->info.enums.enm[i].flags |= LYS_AUTOASSIGNED;
+                    v++;
                 }
-                type->info.enums.enm[i].value = v;
-                type->info.enums.enm[i].flags |= LYS_AUTOASSIGNED;
-                v++;
+            } else { /* restricted enum type */
+                if (!val_set) {
+                    /* automatically assign value from base type */
+                    type->info.enums.enm[i].value = enms_sc[j].value;
+                    type->info.enums.enm[i].flags |= LYS_AUTOASSIGNED;
+                } else {
+                    /* check that the assigned value corresponds to the original
+                     * value of the enum in the base type */
+                    if (v_ != enms_sc[j].value) {
+                        /* v_ - assigned value in restricted enum
+                         * enms_sc[j].value - value assigned to the corresponding enum (detected above) in base type */
+                        LOGVAL(LYE_ENUM_INVAL, LY_VLOG_NONE, NULL,
+                               type->info.enums.enm[i].value, type->info.enums.enm[i].name);
+                        type->info.enums.count = i + 1;
+                        goto error;
+                    }
+                }
             }
         }
         break;