schema compile CHANGE support for enumeration and bits types
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 7049feb..052b87a 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -35,7 +35,7 @@
     "16bit unsigned integer", "32bit integer", "32bit unsigned integer", "64bit integer", "64bit unsigned integer"
 };
 
-#define FREE_ARRAY(CTX, ARRAY, FUNC) {uint64_t c__; LY_ARRAY_FOR(ARRAY, c__){FUNC(CTX, &ARRAY[c__]);}LY_ARRAY_FREE(ARRAY);}
+#define FREE_ARRAY(CTX, ARRAY, FUNC) {uint64_t c__; LY_ARRAY_FOR(ARRAY, c__){FUNC(CTX, &(ARRAY)[c__]);}LY_ARRAY_FREE(ARRAY);}
 #define FREE_MEMBER(CTX, MEMBER, FUNC) if (MEMBER) {FUNC(CTX, MEMBER);free(MEMBER);}
 #define FREE_STRING(CTX, STRING) if (STRING) {lydict_remove(CTX, STRING);}
 #define FREE_STRINGS(CTX, ARRAY) {uint64_t c__; LY_ARRAY_FOR(ARRAY, c__){FREE_STRING(CTX, ARRAY[c__]);}LY_ARRAY_FREE(ARRAY);}
@@ -588,6 +588,14 @@
 }
 
 static void
+lysc_enum_item_free(struct ly_ctx *ctx, struct lysc_type_enum_item *item)
+{
+    FREE_STRING(ctx, item->name);
+    FREE_ARRAY(ctx, item->iffeatures, lysc_iffeature_free);
+    FREE_ARRAY(ctx, item->exts, lysc_ext_instance_free);
+}
+
+static void
 lysc_type_free(struct ly_ctx *ctx, struct lysc_type *type)
 {
     if (--type->refcount) {
@@ -597,10 +605,16 @@
     case LY_TYPE_BINARY:
         FREE_MEMBER(ctx, ((struct lysc_type_bin*)type)->length, lysc_range_free);
         break;
+    case LY_TYPE_BITS:
+        FREE_ARRAY(ctx, (struct lysc_type_enum_item*)((struct lysc_type_bits*)type)->bits, lysc_enum_item_free);
+        break;
     case LY_TYPE_STRING:
         FREE_MEMBER(ctx, ((struct lysc_type_str*)type)->length, lysc_range_free);
         FREE_ARRAY(ctx, ((struct lysc_type_str*)type)->patterns, lysc_pattern_free);
         break;
+    case LY_TYPE_ENUM:
+        FREE_ARRAY(ctx, ((struct lysc_type_enum*)type)->enums, lysc_enum_item_free);
+        break;
     case LY_TYPE_INT8:
     case LY_TYPE_UINT8:
     case LY_TYPE_INT16:
@@ -2144,6 +2158,125 @@
 };
 
 static LY_ERR
+lys_compile_type_enums(struct lysc_ctx *ctx, struct lysp_type_enum *enums_p, LY_DATA_TYPE basetype, int options,
+                       struct lysc_type_enum_item *base_enums, struct lysc_type_enum_item **enums)
+{
+    LY_ERR ret = LY_SUCCESS;
+    unsigned int u, v, match;
+    int32_t value = 0;
+    uint32_t position = 0;
+    struct lysc_type_enum_item *e;
+
+    LY_ARRAY_FOR(enums_p, u) {
+        LY_ARRAY_NEW_RET(ctx->ctx, *enums, e, LY_EMEM);
+        DUP_STRING(ctx->ctx, e->name, enums_p[u].name);
+        if (base_enums) {
+            /* check the enum/bit presence in the base type - the set of enums/bits in the derived type must be a subset */
+            LY_ARRAY_FOR(base_enums, v) {
+                if (!strcmp(e->name, base_enums[v].name)) {
+                    break;
+                }
+            }
+            if (v == LY_ARRAY_SIZE(base_enums)) {
+                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
+                       "Invalid %s - derived type adds new item \"%s\".",
+                       basetype == LY_TYPE_ENUM ? "enumeration" : "bits", e->name);
+                return LY_EVALID;
+            }
+            match = v;
+        }
+
+        if (basetype == LY_TYPE_ENUM) {
+            if (enums_p[u].flags & LYS_SET_VALUE) {
+                e->value = (int32_t)enums_p[u].value;
+                if (!u || e->value >= value) {
+                    value = e->value + 1;
+                }
+                /* check collision with other values */
+                for (v = 0; v < LY_ARRAY_SIZE(*enums) - 1; ++v) {
+                    if (e->value == (*enums)[v].value) {
+                        LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
+                               "Invalid enumeration - value %d collide in items \"%s\" and \"%s\".",
+                               e->value, e->name, (*enums)[v].name);
+                        return LY_EVALID;
+                    }
+                }
+            } else if (base_enums) {
+                /* inherit the assigned value */
+                e->value = base_enums[match].value;
+                if (!u || e->value >= value) {
+                    value = e->value + 1;
+                }
+            } else {
+                /* assign value automatically */
+                if (u && value == INT32_MIN) {
+                    /* counter overflow */
+                    LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
+                           "Invalid enumeration - it is not possible to auto-assign enum value for "
+                           "\"%s\" since the highest value is already 2147483647.", e->name);
+                    return LY_EVALID;
+                }
+                e->value = value++;
+            }
+        } else { /* LY_TYPE_BITS */
+            if (enums_p[u].flags & LYS_SET_VALUE) {
+                e->value = (int32_t)enums_p[u].value;
+                if (!u || (uint32_t)e->value >= position) {
+                    position = (uint32_t)e->value + 1;
+                }
+                /* check collision with other values */
+                for (v = 0; v < LY_ARRAY_SIZE(*enums) - 1; ++v) {
+                    if (e->value == (*enums)[v].value) {
+                        LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
+                               "Invalid bits - position %u collide in items \"%s\" and \"%s\".",
+                               (uint32_t)e->value, e->name, (*enums)[v].name);
+                        return LY_EVALID;
+                    }
+                }
+            } else if (base_enums) {
+                /* inherit the assigned value */
+                e->value = base_enums[match].value;
+                if (!u || (uint32_t)e->value >= position) {
+                    position = (uint32_t)e->value + 1;
+                }
+            } else {
+                /* assign value automatically */
+                if (u && position == 0) {
+                    /* counter overflow */
+                    LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
+                           "Invalid bits - it is not possible to auto-assign bit position for "
+                           "\"%s\" since the highest value is already 4294967295.", e->name);
+                    return LY_EVALID;
+                }
+                e->value = position++;
+            }
+        }
+
+        if (base_enums) {
+            /* the assigned values must not change from the derived type */
+            if (e->value != base_enums[match].value) {
+                if (basetype == LY_TYPE_ENUM) {
+                    LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
+                       "Invalid enumeration - value of the item \"%s\" has changed from %d to %d in the derived type.",
+                       e->name, base_enums[match].value, e->value);
+                } else {
+                    LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
+                       "Invalid bits - position of the item \"%s\" has changed from %u to %u in the derived type.",
+                       e->name, (uint32_t)base_enums[match].value, (uint32_t)e->value);
+                }
+                return LY_EVALID;
+            }
+        }
+
+        COMPILE_ARRAY_GOTO(ctx, enums_p[u].iffeatures, e->iffeatures, options, v, lys_compile_iffeature, ret, done);
+        COMPILE_ARRAY_GOTO(ctx, enums_p[u].exts, e->exts, options, u, lys_compile_ext, ret, done);
+    }
+
+done:
+    return ret;
+}
+
+static LY_ERR
 lys_compile_type(struct lysc_ctx *ctx, struct lysp_node_leaf *leaf_p, int options, struct lysc_type **type)
 {
     LY_ERR ret = LY_SUCCESS;
@@ -2157,9 +2290,11 @@
     LY_DATA_TYPE basetype = LY_TYPE_UNKNOWN;
     struct lysc_type *base = NULL;
     struct ly_set tpdf_chain = {0};
-    struct lysc_type_bin* bin;
-    struct lysc_type_num* num;
-    struct lysc_type_str* str;
+    struct lysc_type_bin *bin;
+    struct lysc_type_num *num;
+    struct lysc_type_str *str;
+    struct lysc_type_bits *bits;
+    struct lysc_type_enum *enumeration;
 
     (*type) = NULL;
 
@@ -2205,6 +2340,7 @@
         break;
     case LY_TYPE_BITS:
         *type = calloc(1, sizeof(struct lysc_type_bits));
+        bits = (struct lysc_type_bits*)(*type);
         break;
     case LY_TYPE_BOOL:
     case LY_TYPE_EMPTY:
@@ -2215,6 +2351,7 @@
         break;
     case LY_TYPE_ENUM:
         *type = calloc(1, sizeof(struct lysc_type_enum));
+        enumeration = (struct lysc_type_enum*)(*type);
         break;
     case LY_TYPE_IDENT:
         *type = calloc(1, sizeof(struct lysc_type_identityref));
@@ -2292,6 +2429,29 @@
             *type = calloc(1, sizeof(struct lysc_type_bin));
             bin = (struct lysc_type_bin*)(*type);
             break;
+        case LY_TYPE_BITS:
+            /* RFC 6020 9.6 - enum */
+            if (tctx->tpdf->type.bits) {
+                ret = lys_compile_type_enums(ctx, tctx->tpdf->type.bits, basetype, options,
+                                             base ? (struct lysc_type_enum_item*)((struct lysc_type_bits*)base)->bits : NULL,
+                                             (struct lysc_type_enum_item**)&bits->bits);
+                LY_CHECK_GOTO(ret, cleanup);
+            }
+
+            if ((u == tpdf_chain.count - 1) && !(tctx->tpdf->type.flags)) {
+                /* type derived from bits built-in type must contain at least one bit */
+                if (!bits->bits) {
+                    LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
+                           "Missing bit substatement for bits type \"%s\".", tctx->tpdf->name);
+                    ret = LY_EVALID;
+                    goto cleanup;
+                }
+            }
+
+            base = ((struct lysp_tpdf*)tctx->tpdf)->type.compiled = *type;
+            *type = calloc(1, sizeof(struct lysc_type_bits));
+            bits = (struct lysc_type_bits*)(*type);
+            break;
         case LY_TYPE_STRING:
             /* RFC 6020 9.4.4 - length */
             if (tctx->tpdf->type.length) {
@@ -2315,6 +2475,28 @@
             *type = calloc(1, sizeof(struct lysc_type_str));
             str = (struct lysc_type_str*)(*type);
             break;
+        case LY_TYPE_ENUM:
+            /* RFC 6020 9.6 - enum */
+            if (tctx->tpdf->type.enums) {
+                ret = lys_compile_type_enums(ctx, tctx->tpdf->type.enums, basetype, options,
+                                             base ? ((struct lysc_type_enum*)base)->enums : NULL, &enumeration->enums);
+                LY_CHECK_GOTO(ret, cleanup);
+            }
+
+            if ((u == tpdf_chain.count - 1) && !(tctx->tpdf->type.flags)) {
+                /* type derived from enumerations built-in type must contain at least one enum */
+                if (!enumeration->enums) {
+                    LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
+                           "Missing enum substatement for enumeration type \"%s\".", tctx->tpdf->name);
+                    ret = LY_EVALID;
+                    goto cleanup;
+                }
+            }
+
+            base = ((struct lysp_tpdf*)tctx->tpdf)->type.compiled = *type;
+            *type = calloc(1, sizeof(struct lysc_type_enum));
+            enumeration = (struct lysc_type_enum*)(*type);
+            break;
         case LY_TYPE_INT8:
         case LY_TYPE_UINT8:
         case LY_TYPE_INT16:
@@ -2359,6 +2541,14 @@
                                    options, u, lys_compile_ext, ret, cleanup);
             }
             break;
+        case LY_TYPE_BITS:
+            if (leaf_p->type.bits) {
+                ret = lys_compile_type_enums(ctx, leaf_p->type.bits, basetype, options,
+                                             base ? (struct lysc_type_enum_item*)((struct lysc_type_bits*)base)->bits : NULL,
+                                             (struct lysc_type_enum_item**)&bits->bits);
+                LY_CHECK_GOTO(ret, cleanup);
+            }
+            break;
         case LY_TYPE_STRING:
             if (leaf_p->type.length) {
                 ret = lys_compile_type_range(ctx, leaf_p->type.length, basetype, 1,
@@ -2378,6 +2568,13 @@
                 str->patterns = lysc_patterns_dup(ctx->ctx, ((struct lysc_type_str*)base)->patterns);
             }
             break;
+        case LY_TYPE_ENUM:
+            if (leaf_p->type.enums) {
+                ret = lys_compile_type_enums(ctx, leaf_p->type.enums, basetype, options,
+                                             base ? ((struct lysc_type_enum*)base)->enums : NULL, &enumeration->enums);
+                LY_CHECK_GOTO(ret, cleanup);
+            }
+            break;
         case LY_TYPE_INT8:
         case LY_TYPE_UINT8:
         case LY_TYPE_INT16:
@@ -2405,6 +2602,27 @@
         free(*type);
         (*type) = base;
         ++(*type)->refcount;
+    } else {
+        /* there are some limitations on types derived directly from built-in types */
+        if (basetype == LY_TYPE_BITS) {
+            if (!bits->bits) {
+                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
+                       "Missing bit substatement for bits type.");
+                free(*type);
+                *type = NULL;
+                ret = LY_EVALID;
+                goto cleanup;
+            }
+        } else if (basetype == LY_TYPE_ENUM) {
+            if (!enumeration->enums) {
+                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
+                       "Missing enum substatement for enumeration type.");
+                free(*type);
+                *type = NULL;
+                ret = LY_EVALID;
+                goto cleanup;
+            }
+        }
     }
 
     COMPILE_ARRAY_GOTO(ctx, type_p->exts, (*type)->exts, options, u, lys_compile_ext, ret, cleanup);