context FEATURE added LY_CTX_SET_PRIV_PARSED

With this option, libyang sets ::lysc_node.priv pointers
as a reference to the corresponding ::lysp_node.
This was introduced due to the printer tree module (RFC 8340),
which needs both a compiled and a parsed tree to print.
diff --git a/src/context.c b/src/context.c
index 7ef2cde..de6e4c3 100644
--- a/src/context.c
+++ b/src/context.c
@@ -473,12 +473,30 @@
 API LY_ERR
 ly_ctx_set_options(struct ly_ctx *ctx, uint16_t option)
 {
+    LY_ERR lyrc;
     LY_CHECK_ARG_RET(ctx, ctx, LY_EINVAL);
     LY_CHECK_ERR_RET(option & LY_CTX_NO_YANGLIBRARY, LOGARG(ctx, option), LY_EINVAL);
+    lyrc = LY_SUCCESS;
+
+    if (!(ctx->flags & LY_CTX_SET_PRIV_PARSED) && (option & LY_CTX_SET_PRIV_PARSED)) {
+        ctx->flags |= LY_CTX_SET_PRIV_PARSED;
+        if ((lyrc = lys_recompile(ctx, 0))) {
+            ly_ctx_unset_options(ctx, LY_CTX_SET_PRIV_PARSED);
+        }
+    }
 
     /* set the option(s) */
-    ctx->flags |= option;
+    if (!lyrc) {
+        ctx->flags |= option;
+    }
 
+    return lyrc;
+}
+
+static LY_ERR
+lysc_node_clear_priv_dfs_cb(struct lysc_node *node, void *UNUSED(data), ly_bool *UNUSED(dfs_continue))
+{
+    node->priv = NULL;
     return LY_SUCCESS;
 }
 
@@ -488,6 +506,22 @@
     LY_CHECK_ARG_RET(ctx, ctx, LY_EINVAL);
     LY_CHECK_ERR_RET(option & LY_CTX_NO_YANGLIBRARY, LOGARG(ctx, option), LY_EINVAL);
 
+    if ((ctx->flags & LY_CTX_SET_PRIV_PARSED) && (option & LY_CTX_SET_PRIV_PARSED)) {
+        struct lys_module *mod;
+        uint32_t index;
+
+        index = 0;
+        while ((mod = (struct lys_module *)ly_ctx_get_module_iter(ctx, &index))) {
+            /* ignore modules that didn't compile */
+            if (!mod->compiled) {
+                continue;
+            }
+
+            /* set NULL for all ::lysc_node.priv pointers in module */
+            lysc_module_dfs_full(mod, lysc_node_clear_priv_dfs_cb, NULL);
+        }
+    }
+
     /* unset the option(s) */
     ctx->flags &= ~option;
 
diff --git a/src/context.h b/src/context.h
index eba0fa2..cda1212 100644
--- a/src/context.h
+++ b/src/context.h
@@ -185,6 +185,12 @@
                                         directory, which is by default searched automatically (despite not
                                         recursively). */
 #define LY_CTX_PREFER_SEARCHDIRS 0x20 /**< When searching for schema, prefer searchdirs instead of user callback. */
+#define LY_CTX_SET_PRIV_PARSED 0x40 /**< For all compiled nodes, their private objects (::lysc_node.priv) are used
+                                        by libyang as a reference to the corresponding parsed node (::lysp_node).
+                                        So if this option is set, the user must not change private objects.
+                                        Setting this option by ::ly_ctx_set_options() may result in context recompilation.
+                                        Resetting this option by ::ly_ctx_unset_options() cause that private
+                                        objects will be set to NULL. */
 
 /** @} contextoptions */
 
@@ -314,6 +320,8 @@
  * @brief Set some of the context's options, see @ref contextoptions.
  * @param[in] ctx Context to be modified.
  * @param[in] option Combination of the context's options to be set, see @ref contextoptions.
+ * If there is to be a change to ::LY_CTX_SET_PRIV_PARSED, the context will be recompiled
+ * and all ::lysc_node.priv in the modules will be overwritten, see ::LY_CTX_SET_PRIV_PARSED.
  * @return LY_ERR value.
  */
 LY_ERR ly_ctx_set_options(struct ly_ctx *ctx, uint16_t option);
diff --git a/src/schema_compile_node.c b/src/schema_compile_node.c
index c022261..2808430 100644
--- a/src/schema_compile_node.c
+++ b/src/schema_compile_node.c
@@ -2395,6 +2395,7 @@
     node->module = ctx->cur_mod;
     node->parent = parent;
     node->prev = node;
+    node->priv = ctx->ctx->flags & LY_CTX_SET_PRIV_PARSED ? pnode : NULL;
 
     /* compile any deviations for this node */
     LY_CHECK_GOTO(ret = lys_compile_node_deviations_refines(ctx, pnode, parent, &dev_pnode, &not_supported), error);
diff --git a/src/tree_schema.h b/src/tree_schema.h
index 9be02a3..d54ac09 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -72,7 +72,8 @@
  * the default nodes are not added into any data tree and mandatory nodes are not checked in the data trees.
  *
  * The compiled schema tree nodes are able to hold private objects (::lysc_node.priv as a pointer to a structure,
- * function, variable, ...) used by a caller application.
+ * function, variable, ...) used by a caller application unless ::LY_CTX_SET_PRIV_PARSED is set, in that case
+ * the ::lysc_node.priv pointers are used by libyang.
  * Note that the object is not freed by libyang when the context is being destroyed. So the caller is responsible
  * for freeing the provided structure after the context is destroyed or the private pointer is set to NULL in
  * appropriate schema nodes where the object was previously set. This can be automated via destructor function
@@ -1653,7 +1654,7 @@
     const char *dsc;                 /**< description */
     const char *ref;                 /**< reference */
     struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
-    void *priv;                      /**< private arbitrary user data, not used by libyang */
+    void *priv;                      /**< private arbitrary user data, not used by libyang unless ::LY_CTX_SET_PRIV_PARSED is set */
 };
 
 struct lysc_node_action_inout {
@@ -1671,7 +1672,7 @@
             const char *dsc;         /**< ALWAYS NULL, compatibility member with ::lysc_node */
             const char *ref;         /**< ALWAYS NULL, compatibility member with ::lysc_node */
             struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
-            void *priv;              /** private arbitrary user data, not used by libyang */
+            void *priv;              /** private arbitrary user data, not used by libyang unless ::LY_CTX_SET_PRIV_PARSED is set */
         };
     };
 
@@ -1697,7 +1698,7 @@
             const char *dsc;         /**< description */
             const char *ref;         /**< reference */
             struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
-            void *priv;              /** private arbitrary user data, not used by libyang */
+            void *priv;              /** private arbitrary user data, not used by libyang unless ::LY_CTX_SET_PRIV_PARSED is set */
         };
     };
 
@@ -1727,7 +1728,7 @@
             const char *dsc;         /**< description */
             const char *ref;         /**< reference */
             struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
-            void *priv;              /** private arbitrary user data, not used by libyang */
+            void *priv;              /** private arbitrary user data, not used by libyang unless ::LY_CTX_SET_PRIV_PARSED is set */
         };
     };
 
@@ -1756,7 +1757,7 @@
             const char *dsc;         /**< description */
             const char *ref;         /**< reference */
             struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
-            void *priv;              /**< private arbitrary user data, not used by libyang */
+            void *priv;              /**< private arbitrary user data, not used by libyang unless ::LY_CTX_SET_PRIV_PARSED is set */
         };
     };
 
@@ -1785,7 +1786,7 @@
             const char *dsc;         /**< description */
             const char *ref;         /**< reference */
             struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
-            void *priv;              /**< private arbitrary user data, not used by libyang */
+            void *priv;              /**< private arbitrary user data, not used by libyang unless ::LY_CTX_SET_PRIV_PARSED is set */
         };
     };
 
@@ -1812,7 +1813,7 @@
             const char *dsc;         /**< description */
             const char *ref;         /**< reference */
             struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
-            void *priv;              /**< private arbitrary user data, not used by libyang */
+            void *priv;              /**< private arbitrary user data, not used by libyang unless ::LY_CTX_SET_PRIV_PARSED is set */
         };
     };
 
@@ -1841,7 +1842,7 @@
             const char *dsc;         /**< description */
             const char *ref;         /**< reference */
             struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
-            void *priv;              /**< private arbitrary user data, not used by libyang */
+            void *priv;              /**< private arbitrary user data, not used by libyang unless ::LY_CTX_SET_PRIV_PARSED is set */
         };
     };
 
@@ -1871,7 +1872,7 @@
             const char *dsc;         /**< description */
             const char *ref;         /**< reference */
             struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
-            void *priv;              /**< private arbitrary user data, not used by libyang */
+            void *priv;              /**< private arbitrary user data, not used by libyang unless ::LY_CTX_SET_PRIV_PARSED is set */
         };
     };
 
@@ -1905,7 +1906,7 @@
             const char *dsc;         /**< description */
             const char *ref;         /**< reference */
             struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
-            void *priv;              /**< private arbitrary user data, not used by libyang */
+            void *priv;              /**< private arbitrary user data, not used by libyang unless ::LY_CTX_SET_PRIV_PARSED is set */
         };
     };
 
@@ -1938,7 +1939,7 @@
             const char *dsc;         /**< description */
             const char *ref;         /**< reference */
             struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
-            void *priv;              /**< private arbitrary user data, not used by libyang */
+            void *priv;              /**< private arbitrary user data, not used by libyang unless ::LY_CTX_SET_PRIV_PARSED is set */
         };
     };
 
diff --git a/src/tree_schema_free.c b/src/tree_schema_free.c
index f39c296..c125e7f 100644
--- a/src/tree_schema_free.c
+++ b/src/tree_schema_free.c
@@ -956,6 +956,10 @@
     /* TODO use the destructor, this just suppress warning about unused parameter */
     (void) private_destructor;
 
+    /* TODO if (module->mod->ctx->flags & LY_CTX_SET_PRIV_PARSED) is true, then
+     * don't use the destructor because private pointers are used by libyang.
+     */
+
     if (module) {
         lysc_module_free_(module);
     }