schema compile CHANGE support for enumeration and bits types
diff --git a/src/parser_yang.c b/src/parser_yang.c
index c4f55a6..f45426a 100644
--- a/src/parser_yang.c
+++ b/src/parser_yang.c
@@ -1822,26 +1822,31 @@
 
     if (!word_len || (word[0] == '+') || ((word[0] == '0') && (word_len > 1)) || ((val_kw == YANG_VALUE) && !strncmp(word, "-0", 2))) {
         LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
-        free(buf);
-        return LY_EVALID;
+        goto error;
     }
 
     errno = 0;
     if (val_kw == YANG_VALUE) {
         num = strtol(word, &ptr, 10);
+        if (num < INT64_C(-2147483648) || num > INT64_C(2147483647)) {
+            LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
+            goto error;
+        }
     } else {
         unum = strtoul(word, &ptr, 10);
+        if (unum > UINT64_C(4294967295)) {
+            LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
+            goto error;
+        }
     }
     /* we have not parsed the whole argument */
     if ((size_t)(ptr - word) != word_len) {
         LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
-        free(buf);
-        return LY_EVALID;
+        goto error;
     }
     if (errno == ERANGE) {
         LOGVAL_YANG(ctx, LY_VCODE_OOB, word_len, word, ly_stmt2str(val_kw));
-        free(buf);
-        return LY_EVALID;
+        goto error;
     }
     if (val_kw == YANG_VALUE) {
         *value = num;
@@ -1861,6 +1866,10 @@
         }
     }
     return ret;
+
+error:
+    free(buf);
+    return LY_EVALID;
 }
 
 /**
@@ -1878,16 +1887,40 @@
 {
     LY_ERR ret = LY_SUCCESS;
     char *buf, *word;
-    size_t word_len;
+    size_t word_len, u;
     enum yang_keyword kw;
     struct lysp_type_enum *enm;
 
     LY_ARRAY_NEW_RET(ctx->ctx, *enums, enm, LY_EMEM);
 
     /* get value */
-    LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, &word, &buf, &word_len));
+    LY_CHECK_RET(get_argument(ctx, data, enum_kw == YANG_ENUM ? Y_STR_ARG : Y_IDENTIF_ARG, &word, &buf, &word_len));
+    if (enum_kw == YANG_ENUM) {
+        if (!word_len) {
+            LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Enum name must not be zero-length.");
+            free(buf);
+            return LY_EVALID;
+        } else if (isspace(word[0]) || isspace(word[word_len - 1])) {
+            LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Enum name must not have any leading or trailing whitespaces (\"%.*s\").",
+                        word_len, word);
+            free(buf);
+            return LY_EVALID;
+        } else {
+            for (u = 0; u < word_len; ++u) {
+                if (iscntrl(word[u])) {
+                    LOGWRN(ctx->ctx, "Control characters in enum name should be avoided (\"%.*s\", character number %d).",
+                           word_len, word, u + 1);
+                    break;
+                }
+            }
+        }
+    } else { /* YANG_BIT */
+
+    }
     INSERT_WORD(ctx, buf, enm->name, word, word_len);
 
+    CHECK_UNIQUENESS(ctx, *enums, name, ly_stmt2str(enum_kw), enm->name);
+
     YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret,) {
         switch (kw) {
         case YANG_DESCRIPTION:
@@ -2238,7 +2271,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &type->exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "when");
+            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "type");
             return LY_EVALID;
         }
     }
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);
diff --git a/src/tree_schema.h b/src/tree_schema.h
index 086d384..0b6713a 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -1061,9 +1061,10 @@
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
-    struct {
+    struct lysc_type_enum_item {
         const char *name;            /**< enumeration identifier */
         struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
+        struct lysc_ext_instance *exts;    /**< list of the extension instances ([sized array](@ref sizedarrays)) */
         int32_t value;               /**< integer value associated with the enumeration */
     } *enums;                        /**< enumerations list ([sized array](@ref sizedarrays)), mandatory (at least 1 item) */
 };
@@ -1095,9 +1096,10 @@
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
     LY_DATA_TYPE basetype;           /**< Base type of the type */
     uint32_t refcount;               /**< reference counter for type sharing */
-    struct {
+    struct lysc_type_bits_item {
         const char *name;            /**< bit identifier */
         struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
+        struct lysc_ext_instance *exts;    /**< list of the extension instances ([sized array](@ref sizedarrays)) */
         uint32_t position;           /**< non-negative integer value associated with the bit */
     } *bits;                         /**< bits list ([sized array](@ref sizedarrays)), mandatory (at least 1 item) */
 };