fill_yin_refine(struct lys_node *uses, struct lyxml_elem *yin, struct lys_refine *rfn, struct unres_schema *unres)
{
    struct ly_ctx *ctx = uses->module->ctx;
    struct lys_module *module;
    struct lyxml_elem *sub, *next;
    const char *value;
    char *endptr;
    int f_mand = 0, f_min = 0, f_max = 0;
    int c_must = 0, c_ftrs = 0, c_dflt = 0, c_ext = 0;
    int r;
    unsigned long int val;
    void *reallocated;

    assert(uses);
    module = uses->module; /* shorthand */

    GETVAL(ctx, value, yin, "target-node");
    rfn->target_name = transform_schema2json(module, value);
    if (!rfn->target_name) {
        goto error;
    }

    LY_TREE_FOR_SAFE(yin->child, next, sub) {
        if (!sub->ns) {
            /* garbage */
        } else if (strcmp(sub->ns->value, LY_NSYIN)) {
            /* extension */
            YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ext, rfn->ext_size, "extensions", "refine", error);
            c_ext++;
            continue;

        } else if (!strcmp(sub->name, "description")) {
            if (rfn->dsc) {
                LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, sub->name, yin->name);
                goto error;
            }

            if (lyp_yin_parse_subnode_ext(module, rfn, LYEXT_PAR_REFINE, sub, LYEXT_SUBSTMT_DESCRIPTION, 0, unres)) {
                goto error;
            }

            rfn->dsc = read_yin_subnode(ctx, sub, "text");
            if (!rfn->dsc) {
                goto error;
            }
        } else if (!strcmp(sub->name, "reference")) {
            if (rfn->ref) {
                LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, sub->name, yin->name);
                goto error;
            }

            if (lyp_yin_parse_subnode_ext(module, rfn, LYEXT_PAR_REFINE, sub, LYEXT_SUBSTMT_REFERENCE, 0, unres)) {
                goto error;
            }

            rfn->ref = read_yin_subnode(ctx, sub, "text");
            if (!rfn->ref) {
                goto error;
            }
        } else if (!strcmp(sub->name, "config")) {
            if (rfn->flags & LYS_CONFIG_MASK) {
                LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, sub->name, yin->name);
                goto error;
            }
            GETVAL(ctx, value, sub, "value");
            if (!strcmp(value, "false")) {
                rfn->flags |= LYS_CONFIG_R;
            } else if (!strcmp(value, "true")) {
                rfn->flags |= LYS_CONFIG_W;
            } else {
                LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, sub->name);
                goto error;
            }
            rfn->flags |= LYS_CONFIG_SET;

            if (lyp_yin_parse_subnode_ext(module, rfn, LYEXT_PAR_REFINE, sub, LYEXT_SUBSTMT_CONFIG, 0, unres)) {
                goto error;
            }
        } else if (!strcmp(sub->name, "default")) {
            /* leaf, leaf-list or choice */

            /* check possibility of statements combination */
            if (rfn->target_type) {
                if (c_dflt) {
                    /* multiple defaults are allowed only in leaf-list */
                    if (module->version < 2) {
                        LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, sub->name, yin->name);
                        goto error;
                    }
                    rfn->target_type &= LYS_LEAFLIST;
                } else {
                    if (module->version < 2) {
                        rfn->target_type &= (LYS_LEAF | LYS_CHOICE);
                    } else {
                        /* YANG 1.1 */
                        rfn->target_type &= (LYS_LEAFLIST | LYS_LEAF | LYS_CHOICE);
                    }
                }
                if (!rfn->target_type) {
                    LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, sub->name, yin->name);
                    LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid refine target nodetype for the substatements.");
                    goto error;
                }
            } else {
                if (module->version < 2) {
                    rfn->target_type = LYS_LEAF | LYS_CHOICE;
                } else {
                    /* YANG 1.1 */
                    rfn->target_type = LYS_LEAFLIST | LYS_LEAF | LYS_CHOICE;
                }
            }

            YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_dflt, rfn->dflt_size, "defaults", "refine", error);
            if (lyp_yin_parse_subnode_ext(module, rfn, LYEXT_PAR_REFINE, sub, LYEXT_SUBSTMT_DEFAULT, c_dflt, unres)) {
                goto error;
            }
            c_dflt++;
            continue;
        } else if (!strcmp(sub->name, "mandatory")) {
            /* leaf, choice or anyxml */
            if (f_mand) {
                LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, sub->name, yin->name);
                goto error;
            }
            /* just checking the flags in leaf is not sufficient, we would allow
             * multiple mandatory statements with the "false" value
             */
            f_mand = 1;

            /* check possibility of statements combination */
            if (rfn->target_type) {
                rfn->target_type &= (LYS_LEAF | LYS_CHOICE | LYS_ANYDATA);
                if (!rfn->target_type) {
                    LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, sub->name, yin->name);
                    LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid refine target nodetype for the substatements.");
                    goto error;
                }
            } else {
                rfn->target_type = LYS_LEAF | LYS_CHOICE | LYS_ANYDATA;
            }

            GETVAL(ctx, value, sub, "value");
            if (!strcmp(value, "true")) {
                rfn->flags |= LYS_MAND_TRUE;
            } else if (!strcmp(value, "false")) {
                rfn->flags |= LYS_MAND_FALSE;
            } else {
                LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, sub->name);
                goto error;
            }
            if (lyp_yin_parse_subnode_ext(module, rfn, LYEXT_PAR_REFINE, sub, LYEXT_SUBSTMT_MANDATORY, 0, unres)) {
                goto error;
            }
        } else if (!strcmp(sub->name, "min-elements")) {
            /* list or leaf-list */
            if (f_min) {
                LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, sub->name, yin->name);
                goto error;
            }
            f_min = 1;

            /* check possibility of statements combination */
            if (rfn->target_type) {
                rfn->target_type &= (LYS_LIST | LYS_LEAFLIST);
                if (!rfn->target_type) {
                    LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, sub->name, yin->name);
                    LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid refine target nodetype for the substatements.");
                    goto error;
                }
            } else {
                rfn->target_type = LYS_LIST | LYS_LEAFLIST;
            }

            GETVAL(ctx, value, sub, "value");
            while (isspace(value[0])) {
                value++;
            }

            /* convert it to uint32_t */
            errno = 0;
            endptr = NULL;
            val = strtoul(value, &endptr, 10);
            if (*endptr || value[0] == '-' || errno || val > UINT32_MAX) {
                LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, sub->name);
                goto error;
            }
            rfn->mod.list.min = (uint32_t) val;
            rfn->flags |= LYS_RFN_MINSET;

            if (lyp_yin_parse_subnode_ext(module, rfn, LYEXT_PAR_REFINE, sub, LYEXT_SUBSTMT_MIN, 0, unres)) {
                goto error;
            }
        } else if (!strcmp(sub->name, "max-elements")) {
            /* list or leaf-list */
            if (f_max) {
                LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, sub->name, yin->name);
                goto error;
            }
            f_max = 1;

            /* check possibility of statements combination */
            if (rfn->target_type) {
                rfn->target_type &= (LYS_LIST | LYS_LEAFLIST);
                if (!rfn->target_type) {
                    LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, sub->name, yin->name);
                    LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid refine target nodetype for the substatements.");
                    goto error;
                }
            } else {
                rfn->target_type = LYS_LIST | LYS_LEAFLIST;
            }

            GETVAL(ctx, value, sub, "value");
            while (isspace(value[0])) {
                value++;
            }

            if (!strcmp(value, "unbounded")) {
                rfn->mod.list.max = 0;
            } else {
                /* convert it to uint32_t */
                errno = 0;
                endptr = NULL;
                val = strtoul(value, &endptr, 10);
                if (*endptr || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
                    LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, sub->name);
                    goto error;
                }
                rfn->mod.list.max = (uint32_t) val;
            }
            rfn->flags |= LYS_RFN_MAXSET;

            if (lyp_yin_parse_subnode_ext(module, rfn, LYEXT_PAR_REFINE, sub, LYEXT_SUBSTMT_MAX, 0, unres)) {
                goto error;
            }
        } else if (!strcmp(sub->name, "presence")) {
            /* container */
            if (rfn->mod.presence) {
                LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, sub->name, yin->name);
                goto error;
            }

            /* check possibility of statements combination */
            if (rfn->target_type) {
                rfn->target_type &= LYS_CONTAINER;
                if (!rfn->target_type) {
                    LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, sub->name, yin->name);
                    LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid refine target nodetype for the substatements.");
                    goto error;
                }
            } else {
                rfn->target_type = LYS_CONTAINER;
            }

            GETVAL(ctx, value, sub, "value");
            rfn->mod.presence = lydict_insert(ctx, value, strlen(value));

            if (lyp_yin_parse_subnode_ext(module, rfn, LYEXT_PAR_REFINE, sub, LYEXT_SUBSTMT_PRESENCE, 0, unres)) {
                goto error;
            }
        } else if (!strcmp(sub->name, "must")) {
            /* leaf leaf-list, list, container or anyxml */
            /* check possibility of statements combination */
            if (rfn->target_type) {
                rfn->target_type &= (LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_CONTAINER | LYS_ANYDATA);
                if (!rfn->target_type) {
                    LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, sub->name, yin->name);
                    LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid refine target nodetype for the substatements.");
                    goto error;
                }
            } else {
                rfn->target_type = LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_CONTAINER | LYS_ANYDATA;
            }

            YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_must, rfn->must_size, "musts", "refine", error);
            c_must++;
            continue;

        } else if ((module->version >= 2) && !strcmp(sub->name, "if-feature")) {
            /* leaf, leaf-list, list, container, choice, case, anydata or anyxml */
            /* check possibility of statements combination */
            if (rfn->target_type) {
                rfn->target_type &= (LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_ANYDATA);
                if (!rfn->target_type) {
                    LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, sub->name, yin->name);
                    LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid refine target nodetype for the substatements.");
                    goto error;
                }
            } else {
                rfn->target_type = LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_ANYDATA;
            }

            YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ftrs, rfn->iffeature_size, "if-feature", "refine", error);
            c_ftrs++;
            continue;
        } else {
            LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, sub->name);
            goto error;
        }

        lyxml_free(ctx, sub);
    }

    /* process nodes with cardinality of 0..n */
    if (c_must) {
        rfn->must = calloc(c_must, sizeof *rfn->must);
        LY_CHECK_ERR_GOTO(!rfn->must, LOGMEM(ctx), error);
    }
    if (c_ftrs) {
        rfn->iffeature = calloc(c_ftrs, sizeof *rfn->iffeature);
        LY_CHECK_ERR_GOTO(!rfn->iffeature, LOGMEM(ctx), error);
    }
    if (c_dflt) {
        rfn->dflt = calloc(c_dflt, sizeof *rfn->dflt);
        LY_CHECK_ERR_GOTO(!rfn->dflt, LOGMEM(ctx), error);
    }
    if (c_ext) {
        /* some extensions may be already present from the substatements */
        reallocated = realloc(rfn->ext, (c_ext + rfn->ext_size) * sizeof *rfn->ext);
        LY_CHECK_ERR_GOTO(!reallocated, LOGMEM(ctx), error);
        rfn->ext = reallocated;

        /* init memory */
        memset(&rfn->ext[rfn->ext_size], 0, c_ext * sizeof *rfn->ext);
    }

    LY_TREE_FOR_SAFE(yin->child, next, sub) {
        if (strcmp(sub->ns->value, LY_NSYIN)) {
            /* extension */
            r = lyp_yin_fill_ext(rfn, LYEXT_PAR_REFINE, 0, 0, module, sub, &rfn->ext, &rfn->ext_size, unres);
            if (r) {
                goto error;
            }
        } else if (!strcmp(sub->name, "if-feature")) {
            r = fill_yin_iffeature(uses, 0, sub, &rfn->iffeature[rfn->iffeature_size], unres);
            rfn->iffeature_size++;
            if (r) {
                goto error;
            }
        } else if (!strcmp(sub->name, "must")) {
            r = fill_yin_must(module, sub, &rfn->must[rfn->must_size], unres);
            rfn->must_size++;
            if (r) {
                goto error;
            }
        } else { /* default */
            GETVAL(ctx, value, sub, "value");

            /* check for duplicity */
            for (r = 0; r < rfn->dflt_size; r++) {
                if (ly_strequal(rfn->dflt[r], value, 1)) {
                    LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "default");
                    LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Duplicated default value \"%s\".", value);
                    goto error;
                }
            }
            rfn->dflt[rfn->dflt_size++] = lydict_insert(ctx, value, strlen(value));
        }
    }

    lyp_reduce_ext_list(&rfn->ext, rfn->ext_size, c_ext + rfn->ext_size);

    return EXIT_SUCCESS;

error:
    return EXIT_FAILURE;
}


read_yin_grouping(struct lys_module *module, struct lys_node *parent, struct lyxml_elem *yin, int options,
                  struct unres_schema *unres)
{
    struct ly_ctx *ctx = module->ctx;
    struct lyxml_elem *sub, *next, root;
    struct lys_node *node = NULL;
    struct lys_node *retval;
    struct lys_node_grp *grp;
    int r;
    int c_tpdf = 0, c_ext = 0;
    void *reallocated;

    /* init */
    memset(&root, 0, sizeof root);

    grp = calloc(1, sizeof *grp);
    LY_CHECK_ERR_RETURN(!grp, LOGMEM(ctx), NULL);

    grp->nodetype = LYS_GROUPING;
    grp->prev = (struct lys_node *)grp;
    retval = (struct lys_node *)grp;

    if (read_yin_common(module, parent, retval, LYEXT_PAR_NODE, yin, OPT_IDENT | OPT_MODULE , unres)) {
        goto error;
    }

    LOGDBG(LY_LDGYIN, "parsing %s statement \"%s\"", yin->name, retval->name);

    /* insert the node into the schema tree */
    if (lys_node_addchild(parent, lys_main_module(module), retval, options)) {
        goto error;
    }

    LY_TREE_FOR_SAFE(yin->child, next, sub) {
        if (strcmp(sub->ns->value, LY_NSYIN)) {
            /* extension */
            YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ext, retval->ext_size, "extensions", "grouping", error);
            c_ext++;

        /* data statements */
        } else if (!strcmp(sub->name, "container") ||
                !strcmp(sub->name, "leaf-list") ||
                !strcmp(sub->name, "leaf") ||
                !strcmp(sub->name, "list") ||
                !strcmp(sub->name, "choice") ||
                !strcmp(sub->name, "uses") ||
                !strcmp(sub->name, "grouping") ||
                !strcmp(sub->name, "anyxml") ||
                !strcmp(sub->name, "anydata") ||
                !strcmp(sub->name, "action") ||
                !strcmp(sub->name, "notification")) {
            lyxml_unlink_elem(ctx, sub, 2);
            lyxml_add_child(ctx, &root, sub);

            /* array counters */
        } else if (!strcmp(sub->name, "typedef")) {
            YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_tpdf, grp->tpdf_size, "typedefs", "grouping", error);
            c_tpdf++;
        } else {
            LOGVAL(ctx, LYE_INSTMT, LY_VLOG_LYS, retval, sub->name);
            goto error;
        }
    }

    /* middle part - process nodes with cardinality of 0..n except the data nodes */
    if (c_tpdf) {
        grp->tpdf = calloc(c_tpdf, sizeof *grp->tpdf);
        LY_CHECK_ERR_GOTO(!grp->tpdf, LOGMEM(ctx), error);
    }
    if (c_ext) {
        /* some extensions may be already present from the substatements */
        reallocated = realloc(retval->ext, (c_ext + retval->ext_size) * sizeof *retval->ext);
        LY_CHECK_ERR_GOTO(!reallocated, LOGMEM(ctx), error);
        retval->ext = reallocated;

        /* init memory */
        memset(&retval->ext[retval->ext_size], 0, c_ext * sizeof *retval->ext);
    }
    LY_TREE_FOR_SAFE(yin->child, next, sub) {
        if (strcmp(sub->ns->value, LY_NSYIN)) {
            /* extension */
            r = lyp_yin_fill_ext(retval, LYEXT_PAR_NODE, 0, 0, module, sub, &retval->ext, &retval->ext_size, unres);
            if (r) {
                goto error;
            }
        } else {
            /* typedef */
            r = fill_yin_typedef(module, retval, sub, &grp->tpdf[grp->tpdf_size], unres);
            grp->tpdf_size++;
            if (r) {
                goto error;
            }
        }
    }

    lyp_reduce_ext_list(&retval->ext, retval->ext_size, c_ext + retval->ext_size);

    /* last part - process data nodes */
    if (!root.child) {
        LOGWRN(ctx, "Grouping \"%s\" without children.", retval->name);
    }
    options |= LYS_PARSE_OPT_INGRP;
    LY_TREE_FOR_SAFE(root.child, next, sub) {
        if (!strcmp(sub->name, "container")) {
            node = read_yin_container(module, retval, sub, options, unres);
        } else if (!strcmp(sub->name, "leaf-list")) {
            node = read_yin_leaflist(module, retval, sub, options, unres);
        } else if (!strcmp(sub->name, "leaf")) {
            node = read_yin_leaf(module, retval, sub, options, unres);
        } else if (!strcmp(sub->name, "list")) {
            node = read_yin_list(module, retval, sub, options, unres);
        } else if (!strcmp(sub->name, "choice")) {
            node = read_yin_choice(module, retval, sub, options, unres);
        } else if (!strcmp(sub->name, "uses")) {
            node = read_yin_uses(module, retval, sub, options, unres);
        } else if (!strcmp(sub->name, "grouping")) {
            node = read_yin_grouping(module, retval, sub, options, unres);
        } else if (!strcmp(sub->name, "anyxml")) {
            node = read_yin_anydata(module, retval, sub, LYS_ANYXML, options, unres);
        } else if (!strcmp(sub->name, "anydata")) {
            node = read_yin_anydata(module, retval, sub, LYS_ANYDATA, options, unres);
        } else if (!strcmp(sub->name, "action")) {
            node = read_yin_rpc_action(module, retval, sub, options, unres);
        } else if (!strcmp(sub->name, "notification")) {
            node = read_yin_notif(module, retval, sub, options, unres);
        }
        if (!node) {
            goto error;
        }

        lyxml_free(ctx, sub);
    }

    return retval;

error:
    lys_node_free(ctx, retval, NULL, 0);
    while (root.child) {
        lyxml_free(ctx, root.child);
    }
    return NULL;
}

yin parser BUGFIX invalid memory access

... in case there were some unresolved
extensions.
Fixes #1454
Fixes #1455


lyp_yin_parse_complex_ext(struct lys_module *mod, struct lys_ext_instance_complex *ext, struct lyxml_elem *yin,
                          struct unres_schema *unres)
{
    struct lyxml_elem *next, *node, *child;
    struct lys_type **type;
    void **pp, *p, *reallocated;
    const char *value, *name;
    char *endptr, modifier;
    struct lyext_substmt *info;
    long int v;
    long long int ll;
    unsigned long u;
    int i, j;

#define YIN_STORE_VALUE(TYPE, FROM, TO)           \
    *(TYPE **)TO = malloc(sizeof(TYPE));          \
    if (!*(TYPE **)TO) { LOGMEM(mod->ctx); goto error; }    \
    (**(TYPE **)TO) = (TYPE)FROM;

#define YIN_EXTCOMPLEX_GETPLACE(STMT, TYPE)                                          \
    p = lys_ext_complex_get_substmt(STMT, ext, &info);                               \
    if (!p) {                                                                        \
        LOGVAL(mod->ctx, LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, node->name, node->parent->name); \
        goto error;                                                                  \
    }                                                                                \
    if (info->cardinality < LY_STMT_CARD_SOME && (*(TYPE*)p)) {                      \
        LOGVAL(mod->ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, node->parent->name);     \
        goto error;                                                                  \
    }                                                                                \
    pp = NULL; i = 0;                                                                \
    if (info->cardinality >= LY_STMT_CARD_SOME) {                                    \
        /* there can be multiple instances */                                        \
        pp = p;                                                                      \
        if (!(*pp)) {                                                                \
            *pp = malloc(2 * sizeof(TYPE)); /* allocate initial array */             \
            LY_CHECK_ERR_GOTO(!*pp, LOGMEM(mod->ctx), error);                        \
        } else {                                                                     \
            for (i = 0; (*(TYPE**)pp)[i]; i++);                                      \
        }                                                                            \
        p = &(*(TYPE**)pp)[i];                                                       \
    }
#define YIN_EXTCOMPLEX_ENLARGE(TYPE)                         \
    if (pp) {                                                \
        /* enlarge the array */                              \
        reallocated = realloc(*pp, (i + 2) * sizeof(TYPE*)); \
        LY_CHECK_ERR_GOTO(!reallocated, LOGMEM(mod->ctx), error);      \
        *pp = reallocated;                                   \
        (*(TYPE**)pp)[i + 1] = 0;                            \
    }
#define YIN_EXTCOMPLEX_PARSE_SNODE(STMT, FUNC, ARGS...)                              \
    pp = (void**)yin_getplace_for_extcomplex_node(node, ext, STMT);                  \
    if (!pp) { goto error; }                                                         \
    if (!FUNC(mod, (struct lys_node*)ext, node, ##ARGS, LYS_PARSE_OPT_CFG_NOINHERIT, unres)) { goto error; }
#define YIN_EXTCOMPLEX_PARSE_RESTR(STMT)                                             \
    YIN_EXTCOMPLEX_GETPLACE(STMT, struct lys_restr*);                                \
    GETVAL(mod->ctx, value, node, "value");                                                    \
    *(struct lys_restr **)p = calloc(1, sizeof(struct lys_restr));                   \
    LY_CHECK_ERR_GOTO(!*(struct lys_restr **)p, LOGMEM(mod->ctx), error);            \
    (*(struct lys_restr **)p)->expr = lydict_insert(mod->ctx, value, 0);             \
    if (read_restr_substmt(mod, *(struct lys_restr **)p, node, unres)) {             \
        goto error;                                                                  \
    }                                                                                \
    YIN_EXTCOMPLEX_ENLARGE(struct lys_restr*);

    LY_TREE_FOR_SAFE(yin->child, next, node) {
        if (!node->ns) {
            /* garbage */
        } else if (node->ns == yin->ns && (ext->flags & LYS_YINELEM) && ly_strequal(node->name, ext->def->argument, 1)) {
            /* we have the extension's argument */
            if (ext->arg_value) {
                LOGVAL(mod->ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, yin->name);
                goto error;
            }
            ext->arg_value = node->content;
            node->content = NULL;
        } else if (strcmp(node->ns->value, LY_NSYIN)) {
            /* extension */
            if (lyp_yin_parse_subnode_ext(mod, ext, LYEXT_PAR_EXTINST, node, LYEXT_SUBSTMT_SELF, 0, unres)) {
                goto error;
            }
        } else if (!strcmp(node->name, "description")) {
            if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_DESCRIPTION, 1, "text", unres)) {
                goto error;
            }
        } else if (!strcmp(node->name, "reference")) {
            if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_REFERENCE, 1, "text", unres)) {
                goto error;
            }
        } else if (!strcmp(node->name, "units")) {
            if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_UNITS, 0, "name", unres)) {
                goto error;
            }
        } else if (!strcmp(node->name, "type")) {
            type = (struct lys_type **)yin_getplace_for_extcomplex_struct(node, ext, LY_STMT_TYPE);
            if (!type) {
                goto error;
            }
            /* allocate type structure */
            (*type) = calloc(1, sizeof **type);
            LY_CHECK_ERR_GOTO(!*type, LOGMEM(mod->ctx), error);

            /* HACK for unres */
            lyxml_unlink(mod->ctx, node);
            (*type)->der = (struct lys_tpdf *)node;
            (*type)->parent = (struct lys_tpdf *)ext;

            if (unres_schema_add_node(mod, unres, *type, UNRES_TYPE_DER_EXT, NULL) == -1) {
                (*type)->der = NULL;
                goto error;
            }
            continue; /* skip lyxml_free() */
        } else if (!strcmp(node->name, "typedef")) {
            pp = yin_getplace_for_extcomplex_struct(node, ext, LY_STMT_TYPEDEF);
            if (!pp) {
                goto error;
            }
            /* allocate typedef structure */
            (*pp) = calloc(1, sizeof(struct lys_tpdf));
            LY_CHECK_ERR_GOTO(!*pp, LOGMEM(mod->ctx), error);

            if (fill_yin_typedef(mod, (struct lys_node *)ext, node, *((struct lys_tpdf **)pp), unres)) {
                goto error;
            }
        } else if (!strcmp(node->name, "if-feature")) {
            pp = yin_getplace_for_extcomplex_struct(node, ext, LY_STMT_IFFEATURE);
            if (!pp) {
                goto error;
            }
            /* allocate iffeature structure */
            (*pp) = calloc(1, sizeof(struct lys_iffeature));
            LY_CHECK_ERR_GOTO(!*pp, LOGMEM(mod->ctx), error);

            if (fill_yin_iffeature((struct lys_node *)ext, 0, node, *((struct lys_iffeature **)pp), unres)) {
                goto error;
            }
        } else if (!strcmp(node->name, "status")) {
            p = yin_getplace_for_extcomplex_flags(node, ext, LY_STMT_STATUS, LYS_STATUS_MASK);
            if (!p) {
                goto error;
            }

            GETVAL(mod->ctx, value, node, "value");
            if (!strcmp(value, "current")) {
                *(uint16_t*)p |= LYS_STATUS_CURR;
            } else if (!strcmp(value, "deprecated")) {
                *(uint16_t*)p |= LYS_STATUS_DEPRC;
            } else if (!strcmp(value, "obsolete")) {
                *(uint16_t*)p |= LYS_STATUS_OBSLT;
            } else {
                LOGVAL(mod->ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, node->name);
                goto error;
            }

            if (lyp_yin_parse_subnode_ext(mod, ext, LYEXT_PAR_EXTINST, node, LYEXT_SUBSTMT_STATUS, 0, unres)) {
                goto error;
            }
        } else if (!strcmp(node->name, "config")) {
            if (yin_parse_extcomplex_flag(mod, node, ext, LY_STMT_MANDATORY, "true", "false", LYS_CONFIG_MASK,
                                          LYS_CONFIG_W | LYS_CONFIG_SET, LYS_CONFIG_R | LYS_CONFIG_SET, unres)) {
                goto error;
            }
        } else if (!strcmp(node->name, "argument")) {
            if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_ARGUMENT, 0, "name", unres)) {
                goto error;
            }
        } else if (!strcmp(node->name, "default")) {
            if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_DEFAULT, 0, "value", unres)) {
                goto error;
            }
        } else if (!strcmp(node->name, "mandatory")) {
            if (yin_parse_extcomplex_flag(mod, node, ext, LY_STMT_MANDATORY,
                                         "true", "false", LYS_MAND_MASK, LYS_MAND_TRUE, LYS_MAND_FALSE, unres)) {
                goto error;
            }
        } else if (!strcmp(node->name, "error-app-tag")) {
            if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_ERRTAG, 0, "value", unres)) {
                goto error;
            }
        } else if (!strcmp(node->name, "error-message")) {
            if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_ERRMSG, 1, "value", unres)) {
                goto error;
            }
        } else if (!strcmp(node->name, "prefix")) {
            if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_PREFIX, 0, "value", unres)) {
                goto error;
            }
        } else if (!strcmp(node->name, "namespace")) {
            if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_NAMESPACE, 0, "uri", unres)) {
                goto error;
            }
        } else if (!strcmp(node->name, "presence")) {
            if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_PRESENCE, 0, "value", unres)) {
                goto error;
            }
        } else if (!strcmp(node->name, "revision-date")) {
            if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_REVISIONDATE, 0, "date", unres)) {
                goto error;
            }
        } else if (!strcmp(node->name, "key")) {
            if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_KEY, 0, "value", unres)) {
                goto error;
            }
        } else if (!strcmp(node->name, "base")) {
            if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_BASE, 0, "name", unres)) {
                goto error;
            }
        } else if (!strcmp(node->name, "ordered-by")) {
            if (yin_parse_extcomplex_flag(mod, node, ext, LY_STMT_ORDEREDBY,
                                          "user", "system", LYS_USERORDERED, LYS_USERORDERED, 0, unres)) {
                goto error;
            }
        } else if (!strcmp(node->name, "belongs-to")) {
            if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_BELONGSTO, 0, "module", unres)) {
                goto error;
            }
        } else if (!strcmp(node->name, "contact")) {
            if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_CONTACT, 1, "text", unres)) {
                goto error;
            }
        } else if (!strcmp(node->name, "organization")) {
            if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_ORGANIZATION, 1, "text", unres)) {
                goto error;
            }
        } else if (!strcmp(node->name, "path")) {
            if (yin_parse_extcomplex_str(mod, node, ext, LY_STMT_PATH, 0, "value", unres)) {
                goto error;
            }
        } else if (!strcmp(node->name, "require-instance")) {
            if (yin_parse_extcomplex_bool(mod, node, ext, LY_STMT_REQINSTANCE, "true", "false", unres)) {
                goto error;
            }
        } else if (!strcmp(node->name, "modifier")) {
            if (yin_parse_extcomplex_bool(mod, node, ext, LY_STMT_MODIFIER, "invert-match", NULL, unres)) {
                goto error;
            }
        } else if (!strcmp(node->name, "fraction-digits")) {
            YIN_EXTCOMPLEX_GETPLACE(LY_STMT_DIGITS, uint8_t);

            GETVAL(mod->ctx, value, node, "value");
            v = strtol(value, NULL, 10);

            /* range check */
            if (v < 1 || v > 18) {
                LOGVAL(mod->ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, node->name);
                goto error;
            }

            if (lyp_yin_parse_subnode_ext(mod, ext, LYEXT_PAR_EXTINST, node, LYEXT_SUBSTMT_STATUS, i, unres)) {
                goto error;
            }

            /* store the value */
            (*(uint8_t *)p) = (uint8_t)v;

            YIN_EXTCOMPLEX_ENLARGE(uint8_t);
        } else if (!strcmp(node->name, "max-elements")) {
            YIN_EXTCOMPLEX_GETPLACE(LY_STMT_MAX, uint32_t*);

            GETVAL(mod->ctx, value, node, "value");
            while (isspace(value[0])) {
                value++;
            }

            if (!strcmp(value, "unbounded")) {
                u = 0;
            } else {
                /* convert it to uint32_t */
                errno = 0; endptr = NULL;
                u = strtoul(value, &endptr, 10);
                if (*endptr || value[0] == '-' || errno || u == 0 || u > UINT32_MAX) {
                    LOGVAL(mod->ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, node->name);
                    goto error;
                }
            }

            if (lyp_yin_parse_subnode_ext(mod, ext, LYEXT_PAR_EXTINST, node, LYEXT_SUBSTMT_MAX, i, unres)) {
                goto error;
            }

            /* store the value */
            YIN_STORE_VALUE(uint32_t, u, p)

            YIN_EXTCOMPLEX_ENLARGE(uint32_t*);
        } else if (!strcmp(node->name, "min-elements")) {
            YIN_EXTCOMPLEX_GETPLACE(LY_STMT_MIN, uint32_t*);

            GETVAL(mod->ctx, value, node, "value");
            while (isspace(value[0])) {
                value++;
            }

            /* convert it to uint32_t */
            errno = 0;
            endptr = NULL;
            u = strtoul(value, &endptr, 10);
            if (*endptr || value[0] == '-' || errno || u > UINT32_MAX) {
                LOGVAL(mod->ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, node->name);
                goto error;
            }

            if (lyp_yin_parse_subnode_ext(mod, ext, LYEXT_PAR_EXTINST, node, LYEXT_SUBSTMT_MAX, i, unres)) {
                goto error;
            }

            /* store the value */
            YIN_STORE_VALUE(uint32_t, u, p)

            YIN_EXTCOMPLEX_ENLARGE(uint32_t*);
        } else if (!strcmp(node->name, "value")) {
            YIN_EXTCOMPLEX_GETPLACE(LY_STMT_VALUE, int32_t*);

            GETVAL(mod->ctx, value, node, "value");
            while (isspace(value[0])) {
                value++;
            }

            /* convert it to int32_t */
            ll = strtoll(value, NULL, 10);

            /* range check */
            if (ll < INT32_MIN || ll > INT32_MAX) {
                LOGVAL(mod->ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, node->name);
                goto error;
            }

            if (lyp_yin_parse_subnode_ext(mod, ext, LYEXT_PAR_EXTINST, node, LYEXT_SUBSTMT_VALUE, i, unres)) {
                goto error;
            }

            /* store the value */
            YIN_STORE_VALUE(int32_t, ll, p)

            YIN_EXTCOMPLEX_ENLARGE(int32_t*);
        } else if (!strcmp(node->name, "position")) {
            YIN_EXTCOMPLEX_GETPLACE(LY_STMT_POSITION, uint32_t*);

            GETVAL(mod->ctx, value, node, "value");
            ll = strtoll(value, NULL, 10);

            /* range check */
            if (ll < 0 || ll > UINT32_MAX) {
                LOGVAL(mod->ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, node->name);
                goto error;
            }

            if (lyp_yin_parse_subnode_ext(mod, ext, LYEXT_PAR_EXTINST, node, LYEXT_SUBSTMT_POSITION, i, unres)) {
                goto error;
            }

            /* store the value */
            YIN_STORE_VALUE(uint32_t, ll, p)

            YIN_EXTCOMPLEX_ENLARGE(uint32_t*);
        } else if (!strcmp(node->name, "module")) {
            pp = yin_getplace_for_extcomplex_struct(node, ext, LY_STMT_MODULE);
            if (!pp) {
                goto error;
            }

            *(struct lys_module **)pp = yin_read_module_(mod->ctx, node, NULL, mod->implemented);
            if (!(*pp)) {
                goto error;
            }
        } else if (!strcmp(node->name, "when")) {
            YIN_EXTCOMPLEX_GETPLACE(LY_STMT_WHEN, struct lys_when*);

            *(struct lys_when**)p = read_yin_when(mod, node, unres);
            if (!*(struct lys_when**)p) {
                goto error;
            }

            YIN_EXTCOMPLEX_ENLARGE(struct lys_when*);
        } else if (!strcmp(node->name, "revision")) {
            YIN_EXTCOMPLEX_GETPLACE(LY_STMT_REVISION, struct lys_revision*);

            *(struct lys_revision**)p = calloc(1, sizeof(struct lys_revision));
            LY_CHECK_ERR_GOTO(!*(struct lys_revision**)p, LOGMEM(mod->ctx), error);
            if (fill_yin_revision(mod, node, *(struct lys_revision**)p, unres)) {
                goto error;
            }

            /* check uniqueness of the revision dates - not required by RFC */
            if (pp) {
                for (j = 0; j < i; j++) {
                    if (!strcmp((*(struct lys_revision***)pp)[j]->date, (*(struct lys_revision**)p)->date)) {
                        LOGWRN(mod->ctx, "Module's revisions are not unique (%s).", (*(struct lys_revision**)p)->date);
                    }
                }
            }

            YIN_EXTCOMPLEX_ENLARGE(struct lys_revision*);
        } else if (!strcmp(node->name, "unique")) {
            YIN_EXTCOMPLEX_GETPLACE(LY_STMT_UNIQUE, struct lys_unique*);

            *(struct lys_unique**)p = calloc(1, sizeof(struct lys_unique));
            LY_CHECK_ERR_GOTO(!*(struct lys_unique**)p, LOGMEM(mod->ctx), error);
            if (fill_yin_unique(mod, (struct lys_node*)ext, node, *(struct lys_unique**)p, unres)) {
                goto error;
            }

            if (lyp_yin_parse_subnode_ext(mod, ext, LYEXT_PAR_EXTINST, node, LYEXT_SUBSTMT_UNIQUE, i, unres)) {
                goto error;
            }
            YIN_EXTCOMPLEX_ENLARGE(struct lys_unique*);
        } else if (!strcmp(node->name, "action")) {
            YIN_EXTCOMPLEX_PARSE_SNODE(LY_STMT_ACTION, read_yin_rpc_action);
        } else if (!strcmp(node->name, "anydata")) {
            YIN_EXTCOMPLEX_PARSE_SNODE(LY_STMT_ANYDATA, read_yin_anydata, LYS_ANYDATA);
        } else if (!strcmp(node->name, "anyxml")) {
            YIN_EXTCOMPLEX_PARSE_SNODE(LY_STMT_ANYXML, read_yin_anydata, LYS_ANYXML);
        } else if (!strcmp(node->name, "case")) {
            YIN_EXTCOMPLEX_PARSE_SNODE(LY_STMT_CASE, read_yin_case);
        } else if (!strcmp(node->name, "choice")) {
            YIN_EXTCOMPLEX_PARSE_SNODE(LY_STMT_CHOICE, read_yin_choice);
        } else if (!strcmp(node->name, "container")) {
            YIN_EXTCOMPLEX_PARSE_SNODE(LY_STMT_CONTAINER, read_yin_container);
        } else if (!strcmp(node->name, "grouping")) {
            YIN_EXTCOMPLEX_PARSE_SNODE(LY_STMT_GROUPING, read_yin_grouping);
        } else if (!strcmp(node->name, "output")) {
            YIN_EXTCOMPLEX_PARSE_SNODE(LY_STMT_OUTPUT, read_yin_input_output);
        } else if (!strcmp(node->name, "input")) {
            YIN_EXTCOMPLEX_PARSE_SNODE(LY_STMT_INPUT, read_yin_input_output);
        } else if (!strcmp(node->name, "leaf")) {
            YIN_EXTCOMPLEX_PARSE_SNODE(LY_STMT_LEAF, read_yin_leaf);
        } else if (!strcmp(node->name, "leaf-list")) {
            YIN_EXTCOMPLEX_PARSE_SNODE(LY_STMT_LEAFLIST, read_yin_leaflist);
        } else if (!strcmp(node->name, "list")) {
            YIN_EXTCOMPLEX_PARSE_SNODE(LY_STMT_LIST, read_yin_list);
        } else if (!strcmp(node->name, "notification")) {
            YIN_EXTCOMPLEX_PARSE_SNODE(LY_STMT_NOTIFICATION, read_yin_notif);
        } else if (!strcmp(node->name, "uses")) {
            YIN_EXTCOMPLEX_PARSE_SNODE(LY_STMT_USES, read_yin_uses);
        } else if (!strcmp(node->name, "length")) {
            YIN_EXTCOMPLEX_PARSE_RESTR(LY_STMT_LENGTH);
        } else if (!strcmp(node->name, "must")) {
            pp = yin_getplace_for_extcomplex_struct(node, ext, LY_STMT_MUST);
            if (!pp) {
                goto error;
            }
            /* allocate structure for must */
            (*pp) = calloc(1, sizeof(struct lys_restr));
            LY_CHECK_ERR_GOTO(!*pp, LOGMEM(mod->ctx), error);

            if (fill_yin_must(mod, node, *((struct lys_restr **)pp), unres)) {
                goto error;
            }
        } else if (!strcmp(node->name, "pattern")) {
            YIN_EXTCOMPLEX_GETPLACE(LY_STMT_PATTERN, struct lys_restr*);
            GETVAL(mod->ctx, value, node, "value");
            if (lyp_check_pattern(mod->ctx, value, NULL)) {
                goto error;
            }

            *(struct lys_restr **)p = calloc(1, sizeof(struct lys_restr));
            LY_CHECK_ERR_GOTO(!*(struct lys_restr **)p, LOGMEM(mod->ctx), error);

            modifier = 0x06; /* ACK */
            if (mod->version >= 2) {
                name = NULL;
                LY_TREE_FOR(node->child, child) {
                    if (child->ns && !strcmp(child->ns->value, LY_NSYIN) && !strcmp(child->name, "modifier")) {
                        if (name) {
                            LOGVAL(mod->ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, "modifier", node->name);
                            goto error;
                        }

                        GETVAL(mod->ctx, name, child, "value");
                        if (!strcmp(name, "invert-match")) {
                            modifier = 0x15; /* NACK */
                        } else {
                            LOGVAL(mod->ctx, LYE_INARG, LY_VLOG_NONE, NULL, name, "modifier");
                            goto error;
                        }
                        /* get extensions of the modifier */
                        if (lyp_yin_parse_subnode_ext(mod, *(struct lys_restr **)p, LYEXT_PAR_RESTR, child,
                                                      LYEXT_SUBSTMT_MODIFIER, 0, unres)) {
                            goto error;
                        }
                    }
                }
            }

            /* store the value: modifier byte + value + terminating NULL byte */
            (*(struct lys_restr **)p)->expr = malloc((strlen(value) + 2) * sizeof(char));
            LY_CHECK_ERR_GOTO(!(*(struct lys_restr **)p)->expr, LOGMEM(mod->ctx), error);
            ((char *)(*(struct lys_restr **)p)->expr)[0] = modifier;
            strcpy(&((char *)(*(struct lys_restr **)p)->expr)[1], value);
            lydict_insert_zc(mod->ctx, (char *)(*(struct lys_restr **)p)->expr);

            /* get possible sub-statements */
            if (read_restr_substmt(mod, *(struct lys_restr **)p, node, unres)) {
                goto error;
            }

            YIN_EXTCOMPLEX_ENLARGE(struct lys_restr*);
        } else if (!strcmp(node->name, "range")) {
            YIN_EXTCOMPLEX_PARSE_RESTR(LY_STMT_RANGE);
        } else {
            LOGERR(mod->ctx, ly_errno, "Extension's substatement \"%s\" not supported.", node->name);
        }
        lyxml_free(mod->ctx, node);
    }

    if (ext->substmt && lyp_mand_check_ext(ext, yin->name)) {
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;

error:
    return EXIT_FAILURE;
}


yin_parse_extcomplex_str(struct lys_module *mod, struct lyxml_elem *node,
                         struct lys_ext_instance_complex *ext, LY_STMT stmt,
                         int argelem, const char *argname, struct unres_schema *unres)
{
    int c;
    const char **str, ***p = NULL, *value;
    void *reallocated;
    struct lyext_substmt *info;

    str = lys_ext_complex_get_substmt(stmt, ext, &info);
    if (!str) {
        LOGVAL(mod->ctx, LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, node->name, node->parent->name);
        return EXIT_FAILURE;
    }
    if (info->cardinality < LY_STMT_CARD_SOME && *str) {
        LOGVAL(mod->ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, node->parent->name);
        return EXIT_FAILURE;
    }

    c = 0;
    if (info->cardinality >= LY_STMT_CARD_SOME) {
        /* there can be multiple instances, str is actually const char *** */
        p = (const char ***)str;
        if (!p[0]) {
            /* allocate initial array */
            p[0] = malloc(2 * sizeof(const char *));
            LY_CHECK_ERR_RETURN(!p[0], LOGMEM(mod->ctx), EXIT_FAILURE);
            if (stmt == LY_STMT_BELONGSTO) {
                /* allocate another array for the belongs-to's prefixes */
                p[1] = malloc(2 * sizeof(const char *));
                LY_CHECK_ERR_RETURN(!p[1], LOGMEM(mod->ctx), EXIT_FAILURE);
            } else if (stmt == LY_STMT_ARGUMENT) {
                /* allocate another array for the yin element */
                ((uint8_t **)p)[1] = malloc(2 * sizeof(uint8_t));
                LY_CHECK_ERR_RETURN(!p[1], LOGMEM(mod->ctx), EXIT_FAILURE);
            }
        } else {
            /* get the index in the array to add new item */
            for (c = 0; p[0][c]; c++);
        }
        str = p[0];
    }
    if (lyp_yin_parse_subnode_ext(mod, ext, LYEXT_PAR_EXTINST, node, (LYEXT_SUBSTMT)stmt, c, unres)) {
        return EXIT_FAILURE;
    }

    if (argelem) {
        str[c] = read_yin_subnode(mod->ctx, node, argname);
        if (!str[c]) {
            return EXIT_FAILURE;
        }
    } else {
        str[c] = lyxml_get_attr(node, argname, NULL);
        if (!str[c]) {
            LOGVAL(mod->ctx, LYE_MISSARG, LY_VLOG_NONE, NULL, argname, node->name);
            return EXIT_FAILURE;
        } else {
            str[c] = lydict_insert(mod->ctx, str[c], 0);
        }

        if (stmt == LY_STMT_BELONGSTO) {
            /* get the belongs-to's mandatory prefix substatement */
            if (!node->child) {
                LOGVAL(mod->ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "prefix", node->name);
                return EXIT_FAILURE;
            } else if (strcmp(node->child->name, "prefix")) {
                LOGVAL(mod->ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->child->name);
                return EXIT_FAILURE;
            } else if (node->child->next) {
                LOGVAL(mod->ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->child->next->name);
                return EXIT_FAILURE;
            }
            /* and now finally get the value */
            if (p) {
                str = p[1];
            } else {
                str++;
            }
            str[c] = lyxml_get_attr(node->child, "value", ((void *)0));
            if (!str[c]) {
                LOGVAL(mod->ctx, LYE_MISSARG, LY_VLOG_NONE, NULL, "value", node->child->name);
                return EXIT_FAILURE;
            }
            str[c] = lydict_insert(mod->ctx, str[c], 0);

            if (!str[c] || lyp_yin_parse_subnode_ext(mod, ext, LYEXT_PAR_EXTINST, node->child, LYEXT_SUBSTMT_PREFIX, c, unres)) {
                return EXIT_FAILURE;
            }
        } else if (stmt == LY_STMT_ARGUMENT) {
            str = (p) ? p[1] : str + 1;
            if (!node->child) {
                /* default value of yin element */
                ((uint8_t *)str)[c] = 2;
            } else {
                /* get optional yin-element substatement */
                if (strcmp(node->child->name, "yin-element")) {
                    LOGVAL(mod->ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->child->name);
                    return EXIT_FAILURE;
                } else if (node->child->next) {
                    LOGVAL(mod->ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->child->next->name);
                    return EXIT_FAILURE;
                } else {
                    /* and now finally get the value */
                    value = lyxml_get_attr(node->child, "value", NULL);
                    if (!value) {
                        LOGVAL(mod->ctx, LYE_MISSARG, LY_VLOG_NONE, NULL, "value", node->child->name);
                        return EXIT_FAILURE;
                    }
                    if (ly_strequal(value, "true", 0)) {
                        ((uint8_t *)str)[c] = 1;
                    } else if (ly_strequal(value, "false", 0)) {
                        ((uint8_t *)str)[c] = 2;
                    } else {
                        LOGVAL(mod->ctx, LYE_INARG, LY_VLOG_NONE, NULL, str, node->name);
                        return EXIT_FAILURE;
                    }

                    if (lyp_yin_parse_subnode_ext(mod, ext, LYEXT_PAR_EXTINST, node->child, LYEXT_SUBSTMT_YINELEM, c, unres)) {
                        return EXIT_FAILURE;
                    }
                }
            }
        }
    }
    if (p) {
        /* enlarge the array(s) */
        reallocated = realloc(p[0], (c + 2) * sizeof(const char *));
        if (!reallocated) {
            LOGMEM(mod->ctx);
            lydict_remove(mod->ctx, p[0][c]);
            p[0][c] = NULL;
            return EXIT_FAILURE;
        }
        p[0] = reallocated;
        p[0][c + 1] = NULL;

        if (stmt == LY_STMT_BELONGSTO) {
            /* enlarge the second belongs-to's array with prefixes */
            reallocated = realloc(p[1], (c + 2) * sizeof(const char *));
            if (!reallocated) {
                LOGMEM(mod->ctx);
                lydict_remove(mod->ctx, p[1][c]);
                p[1][c] = NULL;
                return EXIT_FAILURE;
            }
            p[1] = reallocated;
            p[1][c + 1] = NULL;
        } else if (stmt == LY_STMT_ARGUMENT){
            /* enlarge the second argument's array with yin element */
            reallocated = realloc(p[1], (c + 2) * sizeof(uint8_t));
            if (!reallocated) {
                LOGMEM(mod->ctx);
                ((uint8_t *)p[1])[c] = 0;
                return EXIT_FAILURE;
            }
            p[1] = reallocated;
            ((uint8_t *)p[1])[c + 1] = 0;
        }
    }

    return EXIT_SUCCESS;
}


read_restr_substmt(struct lys_module *module, struct lys_restr *restr, struct lyxml_elem *yin,
                   struct unres_schema *unres)
{
    struct lyxml_elem *child, *next;
    const char *value;
    struct ly_ctx *ctx = module->ctx;

    LY_TREE_FOR_SAFE(yin->child, next, child) {
        if (!child->ns) {
            /* garbage */
            continue;
        } else if (strcmp(child->ns->value, LY_NSYIN)) {
            /* extension */
            if (lyp_yin_parse_subnode_ext(module, restr, LYEXT_PAR_RESTR, child, LYEXT_SUBSTMT_SELF, 0, unres)) {
                return EXIT_FAILURE;
            }
        } else if (!strcmp(child->name, "description")) {
            if (restr->dsc) {
                LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
                return EXIT_FAILURE;
            }
            if (lyp_yin_parse_subnode_ext(module, restr, LYEXT_PAR_RESTR, child, LYEXT_SUBSTMT_DESCRIPTION, 0, unres)) {
                return EXIT_FAILURE;
            }
            restr->dsc = read_yin_subnode(ctx, child, "text");
            if (!restr->dsc) {
                return EXIT_FAILURE;
            }
        } else if (!strcmp(child->name, "reference")) {
            if (restr->ref) {
                LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
                return EXIT_FAILURE;
            }
            if (lyp_yin_parse_subnode_ext(module, restr, LYEXT_PAR_RESTR, child, LYEXT_SUBSTMT_REFERENCE, 0, unres)) {
                return EXIT_FAILURE;
            }
            restr->ref = read_yin_subnode(ctx, child, "text");
            if (!restr->ref) {
                return EXIT_FAILURE;
            }
        } else if (!strcmp(child->name, "error-app-tag")) {
            if (restr->eapptag) {
                LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
                return EXIT_FAILURE;
            }
            if (lyp_yin_parse_subnode_ext(module, restr, LYEXT_PAR_RESTR, child, LYEXT_SUBSTMT_ERRTAG, 0, unres)) {
                return EXIT_FAILURE;
            }
            GETVAL(ctx, value, child, "value");
            restr->eapptag = lydict_insert(ctx, value, 0);
        } else if (!strcmp(child->name, "error-message")) {
            if (restr->emsg) {
                LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, child->name, yin->name);
                return EXIT_FAILURE;
            }
            if (lyp_yin_parse_subnode_ext(module, restr, LYEXT_PAR_RESTR, child, LYEXT_SUBSTMT_ERRMSG, 0, unres)) {
                return EXIT_FAILURE;
            }
            restr->emsg = read_yin_subnode(ctx, child, "value");
            if (!restr->emsg) {
                return EXIT_FAILURE;
            }
        } else {
            LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, child->name);
            return EXIT_FAILURE;
        }
    }

    return EXIT_SUCCESS;

error:
    return EXIT_FAILURE;
}


fill_yin_type(struct lys_module *module, struct lys_node *parent, struct lyxml_elem *yin, struct lys_type *type,
              int parenttype, struct unres_schema *unres)
{
    const char *value, *name, *module_name = NULL;
    struct lys_node *siter;
    struct lyxml_elem *next, *next2, *node, *child, exts;
    struct lys_restr **restrs, *restr;
    struct lys_type_bit bit, *bits_sc = NULL;
    struct lys_type_enum *enms_sc = NULL; /* shortcut */
    struct lys_type *dertype;
    struct ly_ctx *ctx = module->ctx;
    int rc, val_set, c_ftrs, c_ext = 0;
    unsigned int i, j;
    int ret = -1;
    int64_t v, v_ = 0;
    int64_t p, p_;
    size_t len;
    int in_grp = 0;
    char *buf, modifier;

    /* init */
    memset(&exts, 0, sizeof exts);

    GETVAL(ctx, value, yin, "name");
    value = transform_schema2json(module, value);
    if (!value) {
        goto error;
    }

    i = parse_identifier(value);
    if (i < 1) {
        LOGVAL(ctx, LYE_INCHAR, LY_VLOG_NONE, NULL, value[-i], &value[-i]);
        lydict_remove(ctx, value);
        goto error;
    }
    /* module name */
    name = value;
    if (value[i]) {
        module_name = lydict_insert(ctx, value, i);
        name += i;
        if ((name[0] != ':') || (parse_identifier(name + 1) < 1)) {
            LOGVAL(ctx, LYE_INCHAR, LY_VLOG_NONE, NULL, name[0], name);
            lydict_remove(ctx, module_name);
            lydict_remove(ctx, value);
            goto error;
        }
        /* name is in dictionary, but moved */
        ++name;
    }

    rc = resolve_superior_type(name, module_name, module, parent, &type->der);
    if (rc == -1) {
        LOGVAL(ctx, LYE_INMOD, LY_VLOG_NONE, NULL, module_name);
        lydict_remove(ctx, module_name);
        lydict_remove(ctx, value);
        goto error;

    /* the type could not be resolved or it was resolved to an unresolved typedef */
    } else if (rc == EXIT_FAILURE) {
        LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_NONE, NULL, "type", name);
        lydict_remove(ctx, module_name);
        lydict_remove(ctx, value);
        ret = EXIT_FAILURE;
        goto error;
    }
    lydict_remove(ctx, module_name);
    lydict_remove(ctx, value);

    if (type->value_flags & LY_VALUE_UNRESGRP) {
        /* resolved type in grouping, decrease the grouping's nacm number to indicate that one less
         * unresolved item left inside the grouping, LYTYPE_GRP used as a flag for types inside a grouping. */
        for (siter = parent; siter && (siter->nodetype != LYS_GROUPING); siter = lys_parent(siter));
        if (siter) {
            assert(((struct lys_node_grp *)siter)->unres_count);
            ((struct lys_node_grp *)siter)->unres_count--;
        } else {
            LOGINT(ctx);
            goto error;
        }
        type->value_flags &= ~LY_VALUE_UNRESGRP;
    }
    type->base = type->der->type.base;

    /* check status */
    if (lyp_check_status(type->parent->flags, type->parent->module, type->parent->name,
                         type->der->flags, type->der->module, type->der->name,  parent)) {
        return -1;
    }

    /* parse extension instances */
    LY_TREE_FOR_SAFE(yin->child, next, node) {
        if (!node->ns) {
            /* garbage */
            lyxml_free(ctx, node);
            continue;
        } else if (!strcmp(node->ns->value, LY_NSYIN)) {
            /* YANG (YIN) statements - process later */
            continue;
        }

        YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ext, type->ext_size, "extensions", "type", error);

        lyxml_unlink_elem(ctx, node, 2);
        lyxml_add_child(ctx, &exts, node);
        c_ext++;
    }
    if (c_ext) {
        type->ext = calloc(c_ext, sizeof *type->ext);
        LY_CHECK_ERR_GOTO(!type->ext, LOGMEM(ctx), error);

        LY_TREE_FOR_SAFE(exts.child, next, node) {
            rc = lyp_yin_fill_ext(type, LYEXT_PAR_TYPE, 0, 0, module, node, &type->ext, &type->ext_size, unres);
            if (rc) {
                goto error;
            }
        }

        lyp_reduce_ext_list(&type->ext, type->ext_size, c_ext + type->ext_size);
    }

    switch (type->base) {
    case LY_TYPE_BITS:
        /* RFC 6020 9.7.4 - bit */

        /* get bit specifications, at least one must be present */
        LY_TREE_FOR_SAFE(yin->child, next, node) {
            if (!strcmp(node->name, "bit")) {
                YIN_CHECK_ARRAY_OVERFLOW_CODE(ctx, type->info.bits.count, type->info.bits.count, "bits", "type",
                                              type->info.bits.count = 0; goto error);
                type->info.bits.count++;
            } else {
                LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->name);
                type->info.bits.count = 0;
                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(ctx, 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(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, "bit");
                type->info.bits.count = 0;
                goto error;
            }
        }

        if (type->info.bits.count) {
            type->info.bits.bit = calloc(type->info.bits.count, sizeof *type->info.bits.bit);
            LY_CHECK_ERR_GOTO(!type->info.bits.bit, LOGMEM(ctx), error);
        }

        p = 0;
        i = 0;
        LY_TREE_FOR(yin->child, next) {
            c_ftrs = 0;

            GETVAL(ctx, value, next, "name");
            if (lyp_check_identifier(ctx, value, LY_IDENT_SIMPLE, NULL, NULL)) {
                goto error;
            }

            type->info.bits.bit[i].name = lydict_insert(ctx, value, strlen(value));
            if (read_yin_common(module, NULL, &type->info.bits.bit[i], LYEXT_PAR_TYPE_BIT, next, 0, unres)) {
                type->info.bits.count = i + 1;
                goto error;
            }

            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(ctx, 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(ctx, LYE_BITS_INNAME, LY_VLOG_NONE, NULL, value);
                    type->info.bits.count = i + 1;
                    goto error;
                }
            }

            p_ = -1;
            LY_TREE_FOR_SAFE(next->child, next2, node) {
                if (!node->ns) {
                    /* garbage */
                    continue;
                } else if (strcmp(node->ns->value, LY_NSYIN)) {
                    /* extension */
                    if (lyp_yin_parse_subnode_ext(module, &type->info.bits.bit[i], LYEXT_PAR_TYPE_BIT, node,
                                                  LYEXT_SUBSTMT_SELF, 0, unres)) {
                        goto error;
                    }
                } else if (!strcmp(node->name, "position")) {
                    if (p_ != -1) {
                        LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, next->name);
                        type->info.bits.count = i + 1;
                        goto error;
                    }

                    GETVAL(ctx, value, node, "value");
                    p_ = strtoll(value, NULL, 10);

                    /* range check */
                    if (p_ < 0 || p_ > UINT32_MAX) {
                        LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "bit/position");
                        type->info.bits.count = i + 1;
                        goto error;
                    }
                    type->info.bits.bit[i].pos = (uint32_t)p_;

                    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(ctx, 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;
                                }
                            }
                        }
                    }

                    if (lyp_yin_parse_subnode_ext(module, &type->info.bits.bit[i], LYEXT_PAR_TYPE_BIT, node,
                                             LYEXT_SUBSTMT_POSITION, 0, unres)) {
                        goto error;
                    }

                    for (j = 0; j < type->info.bits.bit[i].ext_size; ++j) {
                        /* set flag, which represent LYEXT_OPT_VALID */
                        if (type->info.bits.bit[i].ext[j]->flags & LYEXT_OPT_VALID) {
                            type->parent->flags |= LYS_VALID_EXT;
                            break;
                        }
                    }

                } else if ((module->version >= 2) && !strcmp(node->name, "if-feature")) {
                    YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ftrs, type->info.bits.bit[i].iffeature_size, "if-features", "bit", error);
                    c_ftrs++;
                } else {
                    LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->name);
                    goto error;
                }
            }

            if (!dertype->der) { /* directly derived type from bits built-in type */
                if (p_ == -1) {
                    /* assign value automatically */
                    if (p > UINT32_MAX) {
                        LOGVAL(ctx, 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++;
                }
            } 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(ctx, LYE_BITS_INVAL, LY_VLOG_NONE, NULL, type->info.bits.bit[i].pos,
                               type->info.bits.bit[i].name, bits_sc[j].pos);
                        type->info.bits.count = i + 1;
                        goto error;
                    }
                }
            }

            /* if-features */
            if (c_ftrs) {
                bits_sc = &type->info.bits.bit[i];
                bits_sc->iffeature = calloc(c_ftrs, sizeof *bits_sc->iffeature);
                if (!bits_sc->iffeature) {
                    LOGMEM(ctx);
                    type->info.bits.count = i + 1;
                    goto error;
                }

                LY_TREE_FOR(next->child, node) {
                    if (!strcmp(node->name, "if-feature")) {
                        rc = fill_yin_iffeature((struct lys_node *)type->parent, 0, node,
                                                &bits_sc->iffeature[bits_sc->iffeature_size], unres);
                        bits_sc->iffeature_size++;
                        if (rc) {
                            type->info.bits.count = i + 1;
                            goto error;
                        }
                    }
                }
            }

            /* keep them ordered by position */
            j = i;
            while (j && type->info.bits.bit[j - 1].pos > type->info.bits.bit[j].pos) {
                /* switch them */
                memcpy(&bit, &type->info.bits.bit[j], sizeof bit);
                memcpy(&type->info.bits.bit[j], &type->info.bits.bit[j - 1], sizeof bit);
                memcpy(&type->info.bits.bit[j - 1], &bit, sizeof bit);
                j--;
            }

            ++i;
        }
        break;

    case LY_TYPE_DEC64:
        /* RFC 6020 9.2.4 - range and 9.3.4 - fraction-digits */
        LY_TREE_FOR(yin->child, node) {

            if (!strcmp(node->name, "range")) {
                if (type->info.dec64.range) {
                    LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, yin->name);
                    goto error;
                }

                GETVAL(ctx, value, node, "value");
                type->info.dec64.range = calloc(1, sizeof *type->info.dec64.range);
                LY_CHECK_ERR_GOTO(!type->info.dec64.range, LOGMEM(ctx), error);
                type->info.dec64.range->expr = lydict_insert(ctx, value, 0);

                /* get possible substatements */
                if (read_restr_substmt(module, type->info.dec64.range, node, unres)) {
                    goto error;
                }
                for (j = 0; j < type->info.dec64.range->ext_size; ++j) {
                    /* set flag, which represent LYEXT_OPT_VALID */
                    if (type->info.dec64.range->ext[j]->flags & LYEXT_OPT_VALID) {
                        type->parent->flags |= LYS_VALID_EXT;
                        break;
                    }
                }
            } else if (!strcmp(node->name, "fraction-digits")) {
                if (type->info.dec64.dig) {
                    LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, yin->name);
                    goto error;
                }
                GETVAL(ctx, value, node, "value");
                v = strtol(value, NULL, 10);

                /* range check */
                if (v < 1 || v > 18) {
                    LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, node->name);
                    goto error;
                }
                type->info.dec64.dig = (uint8_t)v;
                type->info.dec64.div = 10;
                for (i = 1; i < v; i++) {
                    type->info.dec64.div *= 10;
                }

                /* extensions */
                if (lyp_yin_parse_subnode_ext(module, type, LYEXT_PAR_TYPE, node, LYEXT_SUBSTMT_DIGITS, 0, unres)) {
                    goto error;
                }
            } else {
                LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->name);
                goto error;
            }
        }

        /* mandatory sub-statement(s) check */
        if (!type->info.dec64.dig && !type->der->type.der) {
            /* decimal64 type directly derived from built-in type requires fraction-digits */
            LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "fraction-digits", "type");
            goto error;
        }
        if (type->info.dec64.dig && type->der->type.der) {
            /* type is not directly derived from buit-in type and fraction-digits statement is prohibited */
            LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, "fraction-digits");
            goto error;
        }

        /* copy fraction-digits specification from parent type for easier internal use */
        if (type->der->type.der) {
            type->info.dec64.dig = type->der->type.info.dec64.dig;
            type->info.dec64.div = type->der->type.info.dec64.div;
        }

        if (type->info.dec64.range && lyp_check_length_range(ctx, type->info.dec64.range->expr, type)) {
            LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "range");
            goto error;
        }
        break;

    case LY_TYPE_ENUM:
        /* RFC 6020 9.6 - enum */

        /* get enum specifications, at least one must be present */
        LY_TREE_FOR_SAFE(yin->child, next, node) {

            if (!strcmp(node->name, "enum")) {
                YIN_CHECK_ARRAY_OVERFLOW_CODE(ctx, type->info.enums.count, type->info.enums.count, "enums", "type",
                                              type->info.enums.count = 0; goto error);
                type->info.enums.count++;
            } else {
                LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->name);
                type->info.enums.count = 0;
                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(ctx, 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(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, "enum");
                type->info.enums.count = 0;
                goto error;
            }
        }

        if (type->info.enums.count) {
            type->info.enums.enm = calloc(type->info.enums.count, sizeof *type->info.enums.enm);
            LY_CHECK_ERR_GOTO(!type->info.enums.enm, LOGMEM(ctx), error);
        }

        v = 0;
        i = 0;
        LY_TREE_FOR(yin->child, next) {
            c_ftrs = 0;

            GETVAL(ctx, value, next, "name");
            if (!value[0]) {
                LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "enum name");
                LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Enum name must not be empty.");
                goto error;
            }
            type->info.enums.enm[i].name = lydict_insert(ctx, value, strlen(value));
            if (read_yin_common(module, NULL, &type->info.enums.enm[i], LYEXT_PAR_TYPE_ENUM, next, 0, unres)) {
                type->info.enums.count = i + 1;
                goto error;
            }

            /* the assigned name MUST NOT have any leading or trailing whitespace characters */
            value = type->info.enums.enm[i].name;
            if (isspace(value[0]) || isspace(value[strlen(value) - 1])) {
                LOGVAL(ctx, LYE_ENUM_WS, LY_VLOG_NONE, NULL, value);
                type->info.enums.count = i + 1;
                goto error;
            }

            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(ctx, 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(ctx, LYE_ENUM_INNAME, LY_VLOG_NONE, NULL, value);
                    type->info.enums.count = i + 1;
                    goto error;
                }
            }

            val_set = 0;
            LY_TREE_FOR_SAFE(next->child, next2, node) {
                if (!node->ns) {
                    /* garbage */
                    continue;
                } else if (strcmp(node->ns->value, LY_NSYIN)) {
                    /* extensions */
                    if (lyp_yin_parse_subnode_ext(module, &type->info.enums.enm[i], LYEXT_PAR_TYPE_ENUM, node,
                                             LYEXT_SUBSTMT_SELF, 0, unres)) {
                        goto error;
                    }
                } else if (!strcmp(node->name, "value")) {
                    if (val_set) {
                        LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, next->name);
                        type->info.enums.count = i + 1;
                        goto error;
                    }

                    GETVAL(ctx, value, node, "value");
                    v_ = strtoll(value, NULL, 10);

                    /* range check */
                    if (v_ < INT32_MIN || v_ > INT32_MAX) {
                        LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "enum/value");
                        type->info.enums.count = i + 1;
                        goto error;
                    }
                    type->info.enums.enm[i].value = v_;

                    if (!dertype->der) { /* directly derived type from enumeration built-in type */
                        if (!i) {
                            /* change value, which is assigned automatically, if first enum has value. */
                            v = type->info.enums.enm[i].value;
                            v++;
                        } else {
                            /* 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(ctx, 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;
                                    }
                                }
                            }
                        }
                    }
                    val_set = 1;

                    if (lyp_yin_parse_subnode_ext(module, &type->info.enums.enm[i], LYEXT_PAR_TYPE_ENUM, node,
                                             LYEXT_SUBSTMT_VALUE, 0, unres)) {
                        goto error;
                    }

                    for (j = 0; j < type->info.enums.enm[i].ext_size; ++j) {
                        /* set flag, which represent LYEXT_OPT_VALID */
                        if (type->info.enums.enm[i].ext[j]->flags & LYEXT_OPT_VALID) {
                            type->parent->flags |= LYS_VALID_EXT;
                            break;
                        }
                    }
                } else if ((module->version >= 2) && !strcmp(node->name, "if-feature")) {
                    YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, c_ftrs, type->info.enums.enm[i].iffeature_size, "if-features", "enum", error);
                    c_ftrs++;

                } else {
                    LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->name);
                    goto error;
                }
            }

            if (!dertype->der) { /* directly derived type from enumeration */
                if (!val_set) {
                    /* assign value automatically */
                    if (v > INT32_MAX) {
                        LOGVAL(ctx, 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++;
                }
            } 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(ctx, LYE_ENUM_INVAL, LY_VLOG_NONE, NULL,
                               type->info.enums.enm[i].value, type->info.enums.enm[i].name, enms_sc[j].value);
                        type->info.enums.count = i + 1;
                        goto error;
                    }
                }
            }

            /* if-features */
            if (c_ftrs) {
                enms_sc = &type->info.enums.enm[i];
                enms_sc->iffeature = calloc(c_ftrs, sizeof *enms_sc->iffeature);
                if (!enms_sc->iffeature) {
                    LOGMEM(ctx);
                    type->info.enums.count = i + 1;
                    goto error;
                }

                LY_TREE_FOR(next->child, node) {
                    if (!strcmp(node->name, "if-feature")) {
                        rc = fill_yin_iffeature((struct lys_node *)type->parent, 0, node,
                                                &enms_sc->iffeature[enms_sc->iffeature_size], unres);
                        enms_sc->iffeature_size++;
                        if (rc) {
                            type->info.enums.count = i + 1;
                            goto error;
                        }
                    }
                }
            }

            ++i;
        }
        break;

    case LY_TYPE_IDENT:
        /* RFC 6020 9.10 - base */

        /* get base specification, at least one must be present */
        LY_TREE_FOR_SAFE(yin->child, next, node) {

            if (strcmp(node->name, "base")) {
                LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->name);
                goto error;
            }

            GETVAL(ctx, value, yin->child, "name");
            /* store in the JSON format */
            value = transform_schema2json(module, value);
            if (!value) {
                goto error;
            }
            rc = unres_schema_add_str(module, unres, type, UNRES_TYPE_IDENTREF, value);
            lydict_remove(ctx, value);
            if (rc == -1) {
                goto error;
            }

            if (lyp_yin_parse_subnode_ext(module, type, LYEXT_PAR_TYPE, node, LYEXT_SUBSTMT_BASE, 0, unres)) {
                goto error;
            }
        }

        if (!yin->child) {
            if (type->der->type.der) {
                /* this is just a derived type with no base required */
                break;
            }
            LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "base", "type");
            goto error;
        } else {
            if (type->der->type.der) {
                LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, "base");
                goto error;
            }
        }
        if (yin->child->next) {
            LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, yin->child->next->name, yin->name);
            goto error;
        }
        break;

    case LY_TYPE_INST:
        /* RFC 6020 9.13.2 - require-instance */
        LY_TREE_FOR(yin->child, node) {
            if (!strcmp(node->name, "require-instance")) {
                if (type->info.inst.req) {
                    LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, yin->name);
                    goto error;
                }
                GETVAL(ctx, value, node, "value");
                if (!strcmp(value, "true")) {
                    type->info.inst.req = 1;
                } else if (!strcmp(value, "false")) {
                    type->info.inst.req = -1;
                } else {
                    LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, node->name);
                    goto error;
                }

                /* extensions */
                if (lyp_yin_parse_subnode_ext(module, type, LYEXT_PAR_TYPE, node, LYEXT_SUBSTMT_REQINSTANCE, 0, unres)) {
                    goto error;
                }
            } else {
                LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->name);
                goto error;
            }
        }

        if (type->der->type.der && !type->info.inst.req) {
            /* inherit require-instance property */
            type->info.inst.req = type->der->type.info.inst.req;
        }

        break;

    case LY_TYPE_BINARY:
        /* RFC 6020 9.8.1, 9.4.4 - length, number of octets it contains */
    case LY_TYPE_INT8:
    case LY_TYPE_INT16:
    case LY_TYPE_INT32:
    case LY_TYPE_INT64:
    case LY_TYPE_UINT8:
    case LY_TYPE_UINT16:
    case LY_TYPE_UINT32:
    case LY_TYPE_UINT64:
        /* RFC 6020 9.2.4 - range */

        /* length and range are actually the same restriction, so process
         * them by this common code, we just need to differ the name and
         * structure where the information will be stored
         */
        if (type->base == LY_TYPE_BINARY) {
            restrs = &type->info.binary.length;
            name = "length";
        } else {
            restrs = &type->info.num.range;
            name = "range";
        }

        LY_TREE_FOR(yin->child, node) {

            if (!strcmp(node->name, name)) {
                if (*restrs) {
                    LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, yin->name);
                    goto error;
                }

                GETVAL(ctx, value, node, "value");
                if (lyp_check_length_range(ctx, value, type)) {
                    LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, name);
                    goto error;
                }
                *restrs = calloc(1, sizeof **restrs);
                LY_CHECK_ERR_GOTO(!(*restrs), LOGMEM(ctx), error);
                (*restrs)->expr = lydict_insert(ctx, value, 0);

                /* get possible substatements */
                if (read_restr_substmt(module, *restrs, node, unres)) {
                    goto error;
                }

                for (j = 0; j < (*restrs)->ext_size; ++j) {
                    /* set flag, which represent LYEXT_OPT_VALID */
                    if ((*restrs)->ext[j]->flags & LYEXT_OPT_VALID) {
                        type->parent->flags |= LYS_VALID_EXT;
                        break;
                    }
                }
            } else {
                LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->name);
                goto error;
            }
        }
        break;

    case LY_TYPE_LEAFREF:
        /* flag resolving for later use */
        if (!parenttype && lys_ingrouping(parent)) {
            /* just a flag - do not resolve */
            parenttype = 1;
        }

        /* RFC 6020 9.9.2 - path */
        LY_TREE_FOR(yin->child, node) {
            if (!strcmp(node->name, "path") && !type->der->type.der) {
                /* keep path for later */
            } else if (module->version >= 2 && !strcmp(node->name, "require-instance")) {
                if (type->info.lref.req) {
                    LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, yin->name);
                    goto error;
                }
                GETVAL(ctx, value, node, "value");
                if (!strcmp(value, "true")) {
                    type->info.lref.req = 1;
                } else if (!strcmp(value, "false")) {
                    type->info.lref.req = -1;
                } else {
                    LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, node->name);
                    goto error;
                }

                /* extensions */
                if (lyp_yin_parse_subnode_ext(module, type, LYEXT_PAR_TYPE, node, LYEXT_SUBSTMT_REQINSTANCE, 0, unres)) {
                    goto error;
                }
            } else {
                LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->name);
                goto error;
            }
        }

        /* now that require-instance is properly set, try to find and resolve path */
        LY_TREE_FOR(yin->child, node) {
            if (!strcmp(node->name, "path") && !type->der->type.der) {
                if (type->info.lref.path) {
                    LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, yin->name);
                    goto error;
                }

                GETVAL(ctx, value, node, "value");
                /* store in the JSON format */
                type->info.lref.path = transform_schema2json(module, value);
                if (!type->info.lref.path) {
                    goto error;
                }

                /* try to resolve leafref path only when this is instantiated
                 * leaf, so it is not:
                 * - typedef's type,
                 * - in  grouping definition,
                 * - just instantiated in a grouping definition,
                 * because in those cases the nodes referenced in path might not be present
                 * and it is not a bug.  */
                if (!parenttype && unres_schema_add_node(module, unres, type, UNRES_TYPE_LEAFREF, parent) == -1) {
                    goto error;
                }

                /* extensions */
                if (lyp_yin_parse_subnode_ext(module, type, LYEXT_PAR_TYPE, node, LYEXT_SUBSTMT_PATH, 0, unres)) {
                    goto error;
                }

                break;
            }
        }

        if (!type->info.lref.path) {
            if (!type->der->type.der) {
                LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "path", "type");
                goto error;
            } else {
                /* copy leafref definition into the derived type */
                type->info.lref.path = lydict_insert(ctx, type->der->type.info.lref.path, 0);
                if (!type->info.lref.req) {
                    type->info.lref.req = type->der->type.info.lref.req;
                }
                /* and resolve the path at the place we are (if not in grouping/typedef) */
                if (!parenttype && unres_schema_add_node(module, unres, type, UNRES_TYPE_LEAFREF, parent) == -1) {
                    goto error;
                }
            }
        }

        break;

    case LY_TYPE_STRING:
        /* RFC 6020 9.4.4 - length */
        /* RFC 6020 9.4.6 - pattern */
        i = 0;
        LY_TREE_FOR_SAFE(yin->child, next, node) {

            if (!strcmp(node->name, "length")) {
                if (type->info.str.length) {
                    LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, yin->name);
                    goto error;
                }

                GETVAL(ctx, value, node, "value");
                if (lyp_check_length_range(ctx, value, type)) {
                    LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "length");
                    goto error;
                }
                type->info.str.length = calloc(1, sizeof *type->info.str.length);
                LY_CHECK_ERR_GOTO(!type->info.str.length, LOGMEM(ctx), error);
                type->info.str.length->expr = lydict_insert(ctx, value, 0);

                /* get possible sub-statements */
                if (read_restr_substmt(module, type->info.str.length, node, unres)) {
                    goto error;
                }

                for (j = 0; j < type->info.str.length->ext_size; ++j) {
                    /* set flag, which represent LYEXT_OPT_VALID */
                    if (type->info.str.length->ext[j]->flags & LYEXT_OPT_VALID) {
                        type->parent->flags |= LYS_VALID_EXT;
                        break;
                    }
                }
                lyxml_free(ctx, node);
            } else if (!strcmp(node->name, "pattern")) {
                YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, i, type->info.str.pat_count, "patterns", "type", error);
                i++;
            } else {
                LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->name);
                goto error;
            }
        }
        /* store patterns in array */
        if (i) {
            if (!parenttype && parent && lys_ingrouping(parent)) {
                in_grp = 1;
            }
            type->info.str.patterns = calloc(i, sizeof *type->info.str.patterns);
            LY_CHECK_ERR_GOTO(!type->info.str.patterns, LOGMEM(ctx), error);
#ifdef LY_ENABLED_CACHE
            if (!in_grp) {
                /* do not compile patterns in groupings */
                type->info.str.patterns_pcre = calloc(2 * i, sizeof *type->info.str.patterns_pcre);
                LY_CHECK_ERR_GOTO(!type->info.str.patterns_pcre, LOGMEM(ctx), error);
            }
#endif
            LY_TREE_FOR(yin->child, node) {
                GETVAL(ctx, value, node, "value");

                if (in_grp) {
                    /* in grouping, just check the pattern syntax */
                    if (!(ctx->models.flags & LY_CTX_TRUSTED) && lyp_check_pattern(ctx, value, NULL)) {
                        goto error;
                    }
                }
#ifdef LY_ENABLED_CACHE
                else {
                    /* outside grouping, check syntax and precompile pattern for later use by libpcre */
                    if (lyp_precompile_pattern(ctx, value,
                            (pcre **)&type->info.str.patterns_pcre[type->info.str.pat_count * 2],
                            (pcre_extra **)&type->info.str.patterns_pcre[type->info.str.pat_count * 2 + 1])) {
                        goto error;
                    }
                }
#endif
                restr = &type->info.str.patterns[type->info.str.pat_count]; /* shortcut */
                type->info.str.pat_count++;

                modifier = 0x06; /* ACK */
                name = NULL;
                if (module->version >= 2) {
                    LY_TREE_FOR_SAFE(node->child, next2, child) {
                        if (child->ns && !strcmp(child->ns->value, LY_NSYIN) && !strcmp(child->name, "modifier")) {
                            if (name) {
                                LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_NONE, NULL, "modifier", node->name);
                                goto error;
                            }

                            GETVAL(ctx, name, child, "value");
                            if (!strcmp(name, "invert-match")) {
                                modifier = 0x15; /* NACK */
                            } else {
                                LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, name, "modifier");
                                goto error;
                            }
                            /* get extensions of the modifier */
                            if (lyp_yin_parse_subnode_ext(module, restr, LYEXT_PAR_RESTR, child,
                                                          LYEXT_SUBSTMT_MODIFIER, 0, unres)) {
                                goto error;
                            }

                            lyxml_free(ctx, child);
                        }
                    }
                }

                len = strlen(value);
                buf = malloc((len + 2) * sizeof *buf); /* modifier byte + value + terminating NULL byte */
                LY_CHECK_ERR_GOTO(!buf, LOGMEM(ctx), error);
                buf[0] = modifier;
                strcpy(&buf[1], value);

                restr->expr = lydict_insert_zc(ctx, buf);

                /* get possible sub-statements */
                if (read_restr_substmt(module, restr, node, unres)) {
                    goto error;
                }

                for (j = 0; j < restr->ext_size; ++j) {
                    /* set flag, which represent LYEXT_OPT_VALID */
                    if (restr->ext[j]->flags & LYEXT_OPT_VALID) {
                        type->parent->flags |= LYS_VALID_EXT;
                        break;
                    }
                }
            }
        }
        break;

    case LY_TYPE_UNION:
        /* RFC 6020 7.4 - type */
        /* count number of types in union */
        i = 0;
        LY_TREE_FOR_SAFE(yin->child, next, node) {

            if (!strcmp(node->name, "type")) {
                if (type->der->type.der) {
                    /* type can be a substatement only in "union" type, not in derived types */
                    LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "type", "derived type");
                    goto error;
                }
                YIN_CHECK_ARRAY_OVERFLOW_GOTO(ctx, i, type->info.uni.count, "types", "type", error);
                i++;
            } else {
                LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, node->name);
                goto error;
            }
        }

        if (!i && !type->der->type.der) {
            LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "type", "(union) type");
            goto error;
        }

        /* inherit instid presence information */
        if ((type->der->type.base == LY_TYPE_UNION) && type->der->type.info.uni.has_ptr_type) {
            type->info.uni.has_ptr_type = 1;
        }

        /* allocate array for union's types ... */
        if (i) {
            type->info.uni.types = calloc(i, sizeof *type->info.uni.types);
            LY_CHECK_ERR_GOTO(!type->info.uni.types, LOGMEM(ctx), error);
        }

        /* ... and fill the structures */
        LY_TREE_FOR(yin->child, node) {
            type->info.uni.types[type->info.uni.count].parent = type->parent;
            rc = fill_yin_type(module, parent, node, &type->info.uni.types[type->info.uni.count], parenttype, unres);
            if (!rc) {
                type->info.uni.count++;

                if (module->version < 2) {
                    /* union's type cannot be empty or leafref */
                    if (type->info.uni.types[type->info.uni.count - 1].base == LY_TYPE_EMPTY) {
                        LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, "empty", node->name);
                        rc = -1;
                    } else if (type->info.uni.types[type->info.uni.count - 1].base == LY_TYPE_LEAFREF) {
                        LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, "leafref", node->name);
                        rc = -1;
                    }
                }

                if ((type->info.uni.types[type->info.uni.count - 1].base == LY_TYPE_INST)
                        || (type->info.uni.types[type->info.uni.count - 1].base == LY_TYPE_LEAFREF)
                        || ((type->info.uni.types[type->info.uni.count - 1].base == LY_TYPE_UNION)
                        && type->info.uni.types[type->info.uni.count - 1].info.uni.has_ptr_type)) {
                    type->info.uni.has_ptr_type = 1;
                }
            }
            if (rc) {
                /* even if we got EXIT_FAILURE, throw it all away, too much trouble doing something else */
                for (i = 0; i < type->info.uni.count; ++i) {
                    lys_type_free(ctx, &type->info.uni.types[i], NULL);
                }
                free(type->info.uni.types);
                type->info.uni.types = NULL;
                type->info.uni.count = 0;
                type->info.uni.has_ptr_type = 0;
                type->der = NULL;
                type->base = LY_TYPE_DER;

                if (rc == EXIT_FAILURE) {
                    ret = EXIT_FAILURE;
                }
                goto error;
            }
        }
        break;

    case LY_TYPE_BOOL:
    case LY_TYPE_EMPTY:
        /* no sub-statement allowed */
        if (yin->child) {
            LOGVAL(ctx, LYE_INSTMT, LY_VLOG_NONE, NULL, yin->child->name);
            goto error;
        }
        break;

    default:
        LOGINT(ctx);
        goto error;
    }

    for(j = 0; j < type->ext_size; ++j) {
        /* set flag, which represent LYEXT_OPT_VALID */
        if (type->ext[j]->flags & LYEXT_OPT_VALID) {
            type->parent->flags |= LYS_VALID_EXT;
            break;
        }
    }

    /* if derived type has extension, which need validate data */
    dertype = &type->der->type;
    while (dertype->der) {
        if (dertype->parent->flags & LYS_VALID_EXT) {
            type->parent->flags |= LYS_VALID_EXT;
        }
        dertype = &dertype->der->type;
    }

    return EXIT_SUCCESS;

error:
    lyxml_free_withsiblings(ctx, exts.child);
    return ret;
}