yin parser: support identityref type
diff --git a/src/log.c b/src/log.c
index aaa2b85..198b5ee 100644
--- a/src/log.c
+++ b/src/log.c
@@ -70,7 +70,7 @@
 		"Missing argument \"%s\" to keyword \"%s\"."},
 		{LY_VERB_ERR,    /* LY_VERR_TOOMANY */
 		"Too many instances of \"%s\" in \"%s\"."},
-		{LY_VERB_ERR,    /* LY_VERR_UNEXP_ARG */
+		{LY_VERB_ERR,    /* LY_VERR_UNEXP_VAL */
 		"Unexpected value \"%s\" of \"%s\"."},
 		{LY_VERB_ERR,    /* LY_VERR_BAD_RESTR */
 		"Restriction \"%s\" not allowed for this base type."},
diff --git a/src/print.c b/src/print.c
index 2f7819e..1a4658c 100644
--- a/src/print.c
+++ b/src/print.c
@@ -94,7 +94,7 @@
 	yang_print_mnode_common(f, level, mnode);
 }
 
-static void yang_print_type(FILE *f, int level, struct ly_type *type)
+static void yang_print_type(FILE *f, int level, struct ly_module *module, struct ly_type *type)
 {
 	int i;
 
@@ -115,6 +115,13 @@
 			fprintf(f, "%*s}\n", LEVEL, INDENT);
 		}
 		break;
+	case LY_TYPE_IDENT:
+		if (module == type->info.ident.ref->module) {
+			fprintf(f, "%*sbase %s;\n", LEVEL, INDENT, type->info.ident.ref->name);
+		} else {
+			fprintf(f, "%*sbase %s:%s;\n", LEVEL, INDENT, type->info.ident.ref->module->prefix, type->info.ident.ref->name);
+		}
+		break;
 	default:
 		/* TODO other cases */
 		break;
@@ -123,13 +130,13 @@
 	fprintf(f, "%*s}\n", LEVEL, INDENT);
 }
 
-static void yang_print_typedef(FILE *f, int level, struct ly_tpdf *tpdf)
+static void yang_print_typedef(FILE *f, int level, struct ly_module *module, struct ly_tpdf *tpdf)
 {
 	fprintf(f, "%*stypedef %s {\n", LEVEL, INDENT, tpdf->name);
 	level++;
 
 	yang_print_mnode_common(f, level, (struct ly_mnode *)tpdf);
-	yang_print_type(f, level, &tpdf->type);
+	yang_print_type(f, level, module, &tpdf->type);
 
 	level--;
 	fprintf(f, "%*s}\n", LEVEL, INDENT);
@@ -165,7 +172,7 @@
 	yang_print_mnode_common2(f, level, mnode);
 
 	for (i = 0; i < cont->tpdf_size; i++) {
-		yang_print_typedef(f, level, &cont->tpdf[i]);
+		yang_print_typedef(f, level, mnode->module, &cont->tpdf[i]);
 	}
 
 	LY_TREE_FOR(mnode->child, sub) {
@@ -200,7 +207,7 @@
 	fprintf(f, "%*sleaf %s {\n", LEVEL, INDENT, mnode->name);
 	level++;
 	yang_print_mnode_common2(f, level, mnode);
-	yang_print_type(f, level, &leaf->type);
+	yang_print_type(f, level, mnode->module, &leaf->type);
 	level--;
 	fprintf(f, "%*s}\n", LEVEL, INDENT);
 }
@@ -212,7 +219,7 @@
 	fprintf(f, "%*sleaf-list %s {\n", LEVEL, INDENT, mnode->name);
 	level++;
 	yang_print_mnode_common2(f, level, mnode);
-	yang_print_type(f, level, &llist->type);
+	yang_print_type(f, level, mnode->module, &llist->type);
 	level--;
 	fprintf(f, "%*s}\n", LEVEL, INDENT);
 }
@@ -228,7 +235,7 @@
 	yang_print_mnode_common2(f, level, mnode);
 
 	for (i = 0; i < list->tpdf_size; i++) {
-		yang_print_typedef(f, level, &list->tpdf[i]);
+		yang_print_typedef(f, level, list->module, &list->tpdf[i]);
 	}
 
 	LY_TREE_FOR(mnode->child, sub) {
@@ -251,7 +258,7 @@
 	yang_print_mnode_common(f, level, mnode);
 
 	for (i = 0; i < grp->tpdf_size; i++) {
-		yang_print_typedef(f, level, &grp->tpdf[i]);
+		yang_print_typedef(f, level, mnode->module, &grp->tpdf[i]);
 	}
 
 	LY_TREE_FOR(mnode->child, node) {
@@ -363,7 +370,7 @@
 	}
 
 	for (i = 0; i < module->tpdf_size; i++) {
-		yang_print_typedef(f, level, &module->tpdf[i]);
+		yang_print_typedef(f, level, module, &module->tpdf[i]);
 	}
 
 	LY_TREE_FOR(module->data, mnode) {
diff --git a/src/tree.h b/src/tree.h
index 760ad5a..e9d60ef 100644
--- a/src/tree.h
+++ b/src/tree.h
@@ -127,8 +127,7 @@
 
 		/* LY_TYPE_IDENT */
 		struct {
-			char *base;
-			struct ly_ident *ident;
+			struct ly_ident *ref;
 		} ident;
 
 		/* LY_TYPE_INST */
diff --git a/src/yin.c b/src/yin.c
index 32879ac..4e29eed 100644
--- a/src/yin.c
+++ b/src/yin.c
@@ -144,6 +144,117 @@
 	return NULL;
 }
 
+static struct ly_ident *find_base_ident(struct ly_module *module, struct ly_ident *ident, const char *basename)
+{
+	const char *name;
+	int prefix_len = 0;
+	int i, found = 0;
+	struct ly_ident *base_iter;
+	struct ly_ident_der *der;
+
+	if (!basename) {
+		ly_verr(LY_VERR_MISS_ARG, "name", "base");
+		return NULL;
+	}
+
+	/* search for the base identity */
+	name = strchr(basename, ':');
+	if (name) {
+		/* set name to correct position after colon */
+		prefix_len = name - basename;
+		name++;
+
+		if (!strncmp(basename, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
+			/* prefix refers to the current module, ignore it */
+			prefix_len = 0;
+		}
+	} else {
+		name = basename;
+	}
+
+	if (prefix_len) {
+		/* get module where to search */
+		for (i = 0; i < module->imp_size; i++) {
+			if (!strncmp(module->imp[i].prefix, basename, prefix_len)
+					&& !module->imp[i].prefix[prefix_len]) {
+				module = module->imp[i].module;
+				found = 1;
+				break;
+			}
+		}
+		if (!found) {
+			/* identity refers unknown data model */
+			ly_verr(LY_VERR_UNEXP_PREFIX, basename);
+			return NULL;
+		}
+	}
+
+	/* search in the identified module */
+	/* TODO what about submodules? */
+	for (i = 0; i < module->ident_size; i++) {
+		if (!strcmp(name, module->ident[i].name)) {
+			/* we are done */
+
+			if (!ident) {
+				/* just search for type, so do not modify anything, just return
+				 * the base identity pointer
+				 */
+				return &module->ident[i];
+			}
+
+			/* we are resolving identity definition, so now update structures */
+			ident->base = base_iter = &module->ident[i];
+
+			while (base_iter) {
+				for (der = base_iter->der; der && der->next; der = der->next);
+				if (der) {
+					der->next = malloc(sizeof *der);
+					der = der->next;
+				} else {
+					ident->base->der = der = malloc(sizeof *der);
+				}
+				der->next = NULL;
+				der->ident = ident;
+
+				base_iter = base_iter->base;
+			}
+			return ident->base;
+		}
+	}
+
+	ly_verr(LY_VERR_UNEXP_VAL, basename, ident ? "identity" : "type");
+	return NULL;
+}
+
+static int fill_yin_identity(struct ly_module *module, struct lyxml_elem *yin, struct ly_ident *ident)
+{
+	struct lyxml_elem *node, *next;
+
+	if (read_yin_common(module, NULL, (struct ly_mnode *)ident, yin, 0)) {
+		return EXIT_FAILURE;
+	}
+	ident->module = module;
+
+	LY_TREE_FOR_SAFE(yin->child, next, node) {
+		if (!strcmp(node->name, "base")) {
+			if (ident->base) {
+				ly_verr(LY_VERR_TOOMANY, "base", "identity");
+				return EXIT_FAILURE;
+			}
+			if (!find_base_ident(module, ident, lyxml_get_attr(node, "name", NULL))) {
+				return EXIT_FAILURE;
+			}
+		} else {
+			ly_verr(LY_VERR_UNEXP_STMT, node->name, "identity");
+			return EXIT_FAILURE;
+		}
+
+		lyxml_free_elem(module->ctx, node);
+	}
+
+	return EXIT_SUCCESS;
+}
+
 static int fill_yin_type(struct ly_module *module, struct ly_mnode *parent,
                          struct lyxml_elem *yin, struct ly_type *type)
 {
@@ -164,7 +275,8 @@
 	switch (type->base) {
 	case LY_TYPE_BINARY:
 		/* length, 9.4.4
-		 * - optional, 0..1, rekurzivni - omezuje, string (podobne jako range), hodnoty se musi vejit do 64b, podelementy
+		 * - optional, 0..1, rekurzivni - omezuje, string (podobne jako range),
+		 * hodnoty se musi vejit do 64b, podelementy
 		 */
 		break;
 	case LY_TYPE_BITS:
@@ -179,10 +291,7 @@
 		break;
 	case LY_TYPE_ENUM:
 		/* RFC 6020 9.6 */
-		if (type->der->module) {
-			ly_verr(LY_VERR_BAD_RESTR, "enum");
-			goto error;
-		}
+
 		/* get enum specification, at least one must be present */
 		LY_TREE_FOR_SAFE(yin->child, next, node) {
 			if (!strcmp(node->name, "enum")) {
@@ -269,8 +378,25 @@
 		}
 		break;
 	case LY_TYPE_IDENT:
-		/* base, 9.10.2
-		 * - 1, nerekurzivni. string */
+		/* RFC 6020 9.10 */
+
+		/* get base specification, exactly one must be present */
+		if (!yin->child) {
+			ly_verr(LY_VERR_MISS_STMT2, "base", "type");
+			goto error;
+		}
+		if (strcmp(yin->child->name, "base")) {
+			ly_verr(LY_VERR_UNEXP_STMT, yin->child->name);
+			goto error;
+		}
+		if (yin->child->next) {
+			ly_verr(LY_VERR_UNEXP_STMT, yin->child->next->name);
+			goto error;
+		}
+		type->info.ident.ref = find_base_ident(module, NULL, lyxml_get_attr(yin->child, "name", NULL));
+		if (!type->info.ident.ref) {
+			return EXIT_FAILURE;
+		}
 		break;
 	case LY_TYPE_INST:
 		/* require-instance, 9.13.2
@@ -435,100 +561,6 @@
 	return EXIT_SUCCESS;
 }
 
-static int fill_yin_identity(struct ly_module *module, struct lyxml_elem *yin, struct ly_ident *ident)
-{
-	const char *basename;
-	struct lyxml_elem *node, *next;
-	const char *name;
-	int prefix_len = 0;
-	int i, found = 0;
-	struct ly_ident *bident;
-	struct ly_ident_der *der;
-
-	if (read_yin_common(module, NULL, (struct ly_mnode *)ident, yin, 0)) {
-		return EXIT_FAILURE;
-	}
-	ident->module = module;
-
-	LY_TREE_FOR_SAFE(yin->child, next, node) {
-		if (!strcmp(node->name, "base")) {
-			if (ident->base) {
-				ly_verr(LY_VERR_TOOMANY, "base", "identity");
-				return EXIT_FAILURE;
-			}
-
-			basename = lyxml_get_attr(node, "name", NULL);
-
-			/* search for the base identity */
-			name = strchr(basename, ':');
-			if (name) {
-				/* set name to correct position after colon */
-				prefix_len = name - basename;
-				name++;
-
-				if (!strncmp(basename, module->prefix, prefix_len) && !module->prefix[prefix_len]) {
-					/* prefix refers to the current module, ignore it */
-					prefix_len = 0;
-				}
-			} else {
-				name = basename;
-			}
-
-			if (prefix_len) {
-				/* get module where to search */
-				for (i = 0; i < module->imp_size; i++) {
-					if (!strncmp(module->imp[i].prefix, basename, prefix_len)
-							&& !module->imp[i].prefix[prefix_len]) {
-						module = module->imp[i].module;
-						found = 1;
-						break;
-					}
-				}
-				if (!found) {
-					/* identity refers unknown data model */
-					ly_verr(LY_VERR_UNEXP_PREFIX, basename);
-					return EXIT_FAILURE;
-				}
-			}
-
-			/* search in the identified module */
-			/* TODO what about submodules? */
-			found = 0;
-			for (i = 0; i < module->ident_size; i++) {
-				if (!strcmp(name, module->ident[i].name)) {
-					/* we are done, now update structures */
-					found = 1;
-
-					ident->base = bident = &module->ident[i];
-
-					while (bident) {
-						for (der = bident->der; der && der->next; der = der->next);
-						if (der) {
-							der->next = malloc(sizeof *der);
-							der = der->next;
-						} else {
-							ident->base->der = der = malloc(sizeof *der);
-						}
-						der->next = NULL;
-						der->ident = ident;
-
-						bident = bident->base;
-					}
-					break;
-				}
-			}
-
-		} else {
-			ly_verr(LY_VERR_UNEXP_STMT, node->name, "identity");
-			return EXIT_FAILURE;
-		}
-
-		lyxml_free_elem(module->ctx, node);
-	}
-
-	return EXIT_SUCCESS;
-}
-
 static struct ly_mnode *read_yin_choice(struct ly_module *module,
                                         struct ly_mnode *parent,
                                         struct lyxml_elem *node)