schema compile CHANGE initial support for RPC/actions

Not yet tested!
diff --git a/src/parser_yang.c b/src/parser_yang.c
index 968bd8e..7916074 100644
--- a/src/parser_yang.c
+++ b/src/parser_yang.c
@@ -2853,27 +2853,23 @@
  * @return LY_ERR values.
  */
 static LY_ERR
-parse_inout(struct ly_parser_ctx *ctx, const char **data, enum yang_keyword inout_kw, struct lysp_node *parent, struct lysp_action_inout **inout_p)
+parse_inout(struct ly_parser_ctx *ctx, const char **data, enum yang_keyword inout_kw, struct lysp_node *parent, struct lysp_action_inout *inout_p)
 {
     LY_ERR ret = LY_SUCCESS;
     char *word;
     size_t word_len;
-    struct lysp_action_inout *inout;
     enum yang_keyword kw;
     unsigned int u;
     struct lysp_node *child;
 
-    if (*inout_p) {
+    if (inout_p->nodetype) {
         LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(inout_kw));
         return LY_EVALID;
     }
 
-    /* create structure */
-    inout = calloc(1, sizeof *inout);
-    LY_CHECK_ERR_RET(!inout, LOGMEM(ctx->ctx), LY_EMEM);
-    *inout_p = inout;
-    inout->nodetype = LYS_INOUT;
-    inout->parent = parent;
+    /* initiate structure */
+    inout_p->nodetype = LYS_INOUT;
+    inout_p->parent = parent;
 
     /* parse substatements */
     YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret,) {
@@ -2882,38 +2878,38 @@
             YANG_CHECK_STMTVER2_RET(ctx, "anydata", ly_stmt2str(inout_kw));
             /* fall through */
         case YANG_ANYXML:
-            LY_CHECK_RET(parse_any(ctx, data, kw, (struct lysp_node*)inout, &inout->data));
+            LY_CHECK_RET(parse_any(ctx, data, kw, (struct lysp_node*)inout_p, &inout_p->data));
             break;
         case YANG_CHOICE:
-            LY_CHECK_RET(parse_choice(ctx, data, (struct lysp_node*)inout, &inout->data));
+            LY_CHECK_RET(parse_choice(ctx, data, (struct lysp_node*)inout_p, &inout_p->data));
             break;
         case YANG_CONTAINER:
-            LY_CHECK_RET(parse_container(ctx, data, (struct lysp_node*)inout, &inout->data));
+            LY_CHECK_RET(parse_container(ctx, data, (struct lysp_node*)inout_p, &inout_p->data));
             break;
         case YANG_LEAF:
-            LY_CHECK_RET(parse_leaf(ctx, data, (struct lysp_node*)inout, &inout->data));
+            LY_CHECK_RET(parse_leaf(ctx, data, (struct lysp_node*)inout_p, &inout_p->data));
             break;
         case YANG_LEAF_LIST:
-            LY_CHECK_RET(parse_leaflist(ctx, data, (struct lysp_node*)inout, &inout->data));
+            LY_CHECK_RET(parse_leaflist(ctx, data, (struct lysp_node*)inout_p, &inout_p->data));
             break;
         case YANG_LIST:
-            LY_CHECK_RET(parse_list(ctx, data, (struct lysp_node*)inout, &inout->data));
+            LY_CHECK_RET(parse_list(ctx, data, (struct lysp_node*)inout_p, &inout_p->data));
             break;
         case YANG_USES:
-            LY_CHECK_RET(parse_uses(ctx, data, (struct lysp_node*)inout, &inout->data));
+            LY_CHECK_RET(parse_uses(ctx, data, (struct lysp_node*)inout_p, &inout_p->data));
             break;
         case YANG_TYPEDEF:
-            LY_CHECK_RET(parse_typedef(ctx, (struct lysp_node*)inout, data, &inout->typedefs));
+            LY_CHECK_RET(parse_typedef(ctx, (struct lysp_node*)inout_p, data, &inout_p->typedefs));
             break;
         case YANG_MUST:
             YANG_CHECK_STMTVER2_RET(ctx, "must", ly_stmt2str(inout_kw));
-            LY_CHECK_RET(parse_restrs(ctx, data, kw, &inout->musts));
+            LY_CHECK_RET(parse_restrs(ctx, data, kw, &inout_p->musts));
             break;
         case YANG_GROUPING:
-            LY_CHECK_RET(parse_grouping(ctx, data, (struct lysp_node*)inout, &inout->groupings));
+            LY_CHECK_RET(parse_grouping(ctx, data, (struct lysp_node*)inout_p, &inout_p->groupings));
             break;
         case YANG_CUSTOM:
-            LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &inout->exts));
+            LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &inout_p->exts));
             break;
         default:
             LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(inout_kw));
@@ -2921,9 +2917,9 @@
         }
     }
     /* finalize parent pointers to the reallocated items */
-    LY_ARRAY_FOR(inout->groupings, u) {
-        LY_LIST_FOR(inout->groupings[u].data, child) {
-            child->parent = (struct lysp_node*)&inout->groupings[u];
+    LY_ARRAY_FOR(inout_p->groupings, u) {
+        LY_LIST_FOR(inout_p->groupings[u].data, child) {
+            child->parent = (struct lysp_node*)&inout_p->groupings[u];
         }
     }
     return ret;
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 6fba4d6..21fc337 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -31,8 +31,12 @@
 API const struct lysc_node *
 lys_getnext(const struct lysc_node *last, const struct lysc_node *parent, const struct lysc_module *module, int options)
 {
-    const struct lysc_node *next;
+    const struct lysc_node *next = NULL;
     struct lysc_node **snode;
+    int action_flag = 0, notif_flag = 0;
+    const struct lysc_action *actions;
+    const struct lysc_notif *notifs;
+    unsigned int u;
 
     LY_CHECK_ARG_RET(NULL, parent || module, NULL);
 
@@ -48,7 +52,7 @@
                 }
                 next = last = (const struct lysc_node*)&((struct lysc_node_choice*)parent)->cases[0];
             } else {
-                snode = lysc_node_children_p(parent);
+                snode = lysc_node_children_p(parent, (options & LYS_GETNEXT_OUTPUT) ? LYS_CONFIG_R : LYS_CONFIG_W);
                 /* do not return anything if the augment does not have any children */
                 if (!snode || !(*snode)) {
                     return NULL;
@@ -60,7 +64,8 @@
             next = last = module->data;
         }
         if (!next) {
-            return next;
+            /* try to get action or notification */
+            goto repeat;
         } else if (!(options & LYS_GETNEXT_NOSTATECHECK)) {
             if (!lys_is_disabled(next, 0)) {
                 return next;
@@ -69,6 +74,36 @@
         } else {
             return next;
         }
+    } else if (last->nodetype == LYS_ACTION) {
+        if (last->parent) {
+            actions = lysc_node_actions(last->parent);
+        } else {
+            actions = module->rpcs;
+        }
+        LY_ARRAY_FOR(actions, u) {
+            if (&actions[u] == (struct lysc_action*)last) {
+                break;
+            }
+        }
+        if (u + 1 < LY_ARRAY_SIZE(actions)) {
+            next = (struct lysc_node*)(&actions[u + 1]);
+        }
+        goto repeat;
+    } else if (last->nodetype == LYS_NOTIF) {
+        if (last->parent) {
+            notifs = lysc_node_notifs(last->parent);
+        } else {
+            notifs = module->notifs;
+        }
+        LY_ARRAY_FOR(notifs, u) {
+            if (&notifs[u] == (struct lysc_notif*)last) {
+                break;
+            }
+        }
+        if (u + 1 < LY_ARRAY_SIZE(notifs)) {
+            next = (struct lysc_node*)(&notifs[u + 1]);
+        }
+        goto repeat;
     }
 
     next = last->next;
@@ -83,9 +118,16 @@
         if (last->parent != parent) {
             last = last->parent;
             next = last->next;
-            goto repeat;
+        } else if (!action_flag) {
+            action_flag = 1;
+            next = parent ? (struct lysc_node*)lysc_node_actions(parent) : (struct lysc_node*)module->rpcs;
+        } else if (!notif_flag) {
+            notif_flag = 1;
+            next = parent ? (struct lysc_node*)lysc_node_notifs(parent) : (struct lysc_node*)module->notifs;
+        } else {
+            return NULL;
         }
-        return next;
+        goto repeat;
     }
     switch (next->nodetype) {
     case LYS_ACTION:
diff --git a/src/tree_schema.h b/src/tree_schema.h
index 376bab4..ea5d3e1 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -161,7 +161,7 @@
 #define LYS_CASE 0x0040           /**< case statement node */
 #define LYS_USES 0x0080           /**< uses statement node */
 #define LYS_INOUT 0x200
-#define LYS_ACTION 0x400
+#define LYS_ACTION 0x400          /**< RPC or action */
 #define LYS_NOTIF 0x800
 #define LYS_GROUPING 0x1000
 #define LYS_AUGMENT 0x2000
@@ -554,9 +554,9 @@
  *                                             1 1 1 1 1
  *     bit name              1 2 3 4 5 6 7 8 9 0 1 2 3 4
  *     ---------------------+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *       1 LYS_CONFIG_W     |x|x|x|x|x|x|x| | |x| | | | |
+ *       1 LYS_CONFIG_W     |x|x|x|x|x|x|x| | | | | | | |
  *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *       2 LYS_CONFIG_R     |x|x|x|x|x|x|x| | | |x| | | |
+ *       2 LYS_CONFIG_R     |x|x|x|x|x|x|x| | | | | | | |
  *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  *       3 LYS_STATUS_CURR  |x|x|x|x|x|x|x|x|x| | |x|x|x|
  *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -841,8 +841,8 @@
     const char **iffeatures;         /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
     struct lysp_tpdf *typedefs;      /**< list of typedefs ([sized array](@ref sizedarrays)) */
     struct lysp_grp *groupings;      /**< list of groupings ([sized array](@ref sizedarrays)) */
-    struct lysp_action_inout *input; /**< RPC's/Action's input */
-    struct lysp_action_inout *output;/**< RPC's/Action's output */
+    struct lysp_action_inout input;  /**< RPC's/Action's input */
+    struct lysp_action_inout output; /**< RPC's/Action's output */
     struct lysp_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
 };
 
@@ -1189,19 +1189,41 @@
     struct lysc_range *length;       /**< Optional length limitation */
 };
 
+struct lysc_action_inout {
+    struct lysc_node *data;          /**< first child node (linked list) */
+    struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
+    struct lysc_must *musts;         /**< list of must restrictions ([sized array](@ref sizedarrays)) */
+};
+
 struct lysc_action {
     uint16_t nodetype;               /**< LYS_ACTION */
     uint16_t flags;                  /**< [schema node flags](@ref snodeflags) */
     struct lys_module *module;       /**< module structure */
+    struct lysp_action *sp;            /**< simply parsed (SP) original of the node, NULL if the SP schema was removed or in case of implicit case node. */
+    struct lysc_node *parent;        /**< parent node (NULL in case of top level node - RPC) */
+
+    struct lysc_ext_instance *exts;  /**< list of the extension instances ([sized array](@ref sizedarrays)) */
+    struct lysc_iffeature *iffeatures; /**< list of if-feature expressions ([sized array](@ref sizedarrays)) */
+
     const char *name;                /**< action/RPC name (mandatory) */
-    /* TODO */
+    const char *dsc;                 /**< description */
+    const char *ref;                 /**< reference */
+
+    struct lysc_action_inout input;  /**< RPC's/action's input */
+    struct lysc_action_inout output; /**< RPC's/action's output */
+
 };
 
 struct lysc_notif {
     uint16_t nodetype;               /**< LYS_NOTIF */
     uint16_t flags;                  /**< [schema node flags](@ref snodeflags) */
     struct lys_module *module;       /**< module structure */
+    struct lysp_notification *sp;    /**< simply parsed (SP) original of the node, NULL if the SP schema was removed or in case of implicit case node. */
+    struct lysc_node *parent;        /**< parent node (NULL in case of top level node) */
+
     const char *name;                /**< Notification name (mandatory) */
+    const char *dsc;                 /**< description */
+    const char *ref;                 /**< reference */
     /* TODO */
 };
 
@@ -1478,9 +1500,10 @@
  * @brief Get the children linked list of the given (compiled) schema node.
  * Decides the node's type and in case it has a children list, returns it.
  * @param[in] node Node to examine.
+ * @param[in] flags Config flag to distinguish input (LYS_CONFIG_W) and output (LYS_CONFIG_R) data in case of RPC/action node.
  * @return The node's children linked list if any, NULL otherwise.
  */
-const struct lysc_node *lysc_node_children(const struct lysc_node *node);
+const struct lysc_node *lysc_node_children(const struct lysc_node *node, uint16_t flags);
 
 /**
  * @brief Get how the if-feature statement currently evaluates.
@@ -1665,6 +1688,8 @@
 #define LYS_GETNEXT_INTONPCONT   0x40 /**< lys_getnext() option to look into non-presence container, instead of returning container itself */
 #define LYS_GETNEXT_NOSTATECHECK 0x100 /**< lys_getnext() option to skip checking module validity (import-only, disabled) and
                                             relevant if-feature conditions state */
+#define LYS_GETNEXT_OUTPUT       0x200 /**< lys_getnext() option to provide RPC's/action's output schema nodes instead of input schema nodes
+                                            provided by default */
 /** @} sgetnextflags */
 
 /**
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index 73cecc9..c2a6a54 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -41,6 +41,17 @@
         } \
     }
 
+#define COMPILE_ARRAY1_GOTO(CTX, ARRAY_P, ARRAY_C, PARENT, OPTIONS, ITER, FUNC, USES_STATUS, RET, GOTO) \
+    if (ARRAY_P) { \
+        LY_ARRAY_CREATE_GOTO((CTX)->ctx, ARRAY_C, LY_ARRAY_SIZE(ARRAY_P), RET, GOTO); \
+        size_t __array_offset = LY_ARRAY_SIZE(ARRAY_C); \
+        for (ITER = 0; ITER < LY_ARRAY_SIZE(ARRAY_P); ++ITER) { \
+            LY_ARRAY_INCREMENT(ARRAY_C); \
+            RET = FUNC(CTX, &(ARRAY_P)[ITER], OPTIONS, PARENT, &(ARRAY_C)[ITER + __array_offset], USES_STATUS); \
+            LY_CHECK_GOTO(RET != LY_SUCCESS, GOTO); \
+        } \
+    }
+
 #define COMPILE_ARRAY_UNIQUE_GOTO(CTX, ARRAY_P, ARRAY_C, OPTIONS, ITER, FUNC, RET, GOTO) \
     if (ARRAY_P) { \
         LY_ARRAY_CREATE_GOTO((CTX)->ctx, ARRAY_C, LY_ARRAY_SIZE(ARRAY_P), RET, GOTO); \
@@ -3004,9 +3015,110 @@
     return ret;
 }
 
+/**
+ * @brief Compile status information of the given node.
+ *
+ * To simplify getting status of the node, the flags are set following inheritance rules, so all the nodes
+ * has the status correctly set during the compilation.
+ *
+ * @param[in] ctx Compile context
+ * @param[in,out] node_flags Flags of the compiled node which status is supposed to be resolved.
+ * If the status was set explicitly on the node, it is already set in the flags value and we just check
+ * the compatibility with the parent's status value.
+ * @param[in] parent_flags Flags of the parent node to check/inherit the status value.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lys_compile_status(struct lysc_ctx *ctx, uint16_t *node_flags, uint16_t parent_flags)
+{
+    /* status - it is not inherited by specification, but it does not make sense to have
+     * current in deprecated or deprecated in obsolete, so we do print warning and inherit status */
+    if (!((*node_flags) & LYS_STATUS_MASK)) {
+        if (parent_flags & (LYS_STATUS_DEPRC | LYS_STATUS_OBSLT)) {
+            if ((parent_flags & 0x3) != 0x3) {
+                /* do not print the warning when inheriting status from uses - the uses_status value has a special
+                 * combination of bits (0x3) which marks the uses_status value */
+                LOGWRN(ctx->ctx, "Missing explicit \"%s\" status that was already specified in parent, inheriting.",
+                       (parent_flags & LYS_STATUS_DEPRC) ? "deprecated" : "obsolete");
+            }
+            (*node_flags) |= parent_flags & LYS_STATUS_MASK;
+        } else {
+            (*node_flags) |= LYS_STATUS_CURR;
+        }
+    } else if (parent_flags & LYS_STATUS_MASK) {
+        /* check status compatibility with the parent */
+        if ((parent_flags & LYS_STATUS_MASK) > ((*node_flags) & LYS_STATUS_MASK)) {
+            if ((*node_flags) & LYS_STATUS_CURR) {
+                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+                       "A \"current\" status is in conflict with the parent's \"%s\" status.",
+                       (parent_flags & LYS_STATUS_DEPRC) ? "deprecated" : "obsolete");
+            } else { /* LYS_STATUS_DEPRC */
+                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+                       "A \"deprecated\" status is in conflict with the parent's \"obsolete\" status.");
+            }
+            return LY_EVALID;
+        }
+    }
+    return LY_SUCCESS;
+}
+
 static LY_ERR lys_compile_node(struct lysc_ctx *ctx, struct lysp_node *node_p, int options, struct lysc_node *parent, uint16_t uses_status);
 
 /**
+ * @brief Compile parsed RPC/action schema node information.
+ * @param[in] ctx Compile context
+ * @param[in] node_p Parsed RPC/action schema node.
+ * @param[in] options Various options to modify compiler behavior, see [compile flags](@ref scflags).
+ * @param[in,out] action Prepared (empty) compiled action structure to fill.
+ * @param[in] uses_status If the RPC/action is being placed instead of uses, here we have the uses's status value (as node's flags).
+ * Zero means no uses, non-zero value with no status bit set mean the default status.
+ * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
+ */
+static LY_ERR
+lys_compile_action(struct lysc_ctx *ctx, struct lysp_action *action_p, int options,
+                   struct lysc_node *parent, struct lysc_action *action, uint16_t uses_status)
+{
+    LY_ERR ret = LY_SUCCESS;
+    struct lysp_node *child_p;
+    unsigned int u;
+
+    action->nodetype = LYS_ACTION;
+    action->module = ctx->mod;
+    action->parent = parent;
+    if (!(options & LYSC_OPT_FREE_SP)) {
+        action->sp = action_p;
+    }
+    action->flags = action_p->flags & LYS_FLAGS_COMPILED_MASK;
+
+    /* status - it is not inherited by specification, but it does not make sense to have
+     * current in deprecated or deprecated in obsolete, so we do print warning and inherit status */
+   LY_CHECK_RET(lys_compile_status(ctx, &action->flags, uses_status ? uses_status : (parent ? parent->flags : 0)));
+
+    DUP_STRING(ctx->ctx, action_p->name, action->name);
+    DUP_STRING(ctx->ctx, action_p->dsc, action->dsc);
+    DUP_STRING(ctx->ctx, action_p->ref, action->ref);
+    COMPILE_ARRAY_GOTO(ctx, action_p->iffeatures, action->iffeatures, options, u, lys_compile_iffeature, ret, cleanup);
+    COMPILE_ARRAY_GOTO(ctx, action_p->exts, action->exts, options, u, lys_compile_ext, ret, cleanup);
+
+    /* input */
+    COMPILE_ARRAY_GOTO(ctx, action_p->input.musts, action->input.musts, options, u, lys_compile_must, ret, cleanup);
+    COMPILE_ARRAY_GOTO(ctx, action_p->input.exts, action->input.exts, options, u, lys_compile_ext, ret, cleanup);
+    LY_LIST_FOR(action_p->input.data, child_p) {
+        LY_CHECK_RET(lys_compile_node(ctx, child_p, options & LYSC_OPT_RPC_INPUT, (struct lysc_node*)action, uses_status));
+    }
+
+    /* output */
+    COMPILE_ARRAY_GOTO(ctx, action_p->output.musts, action->output.musts, options, u, lys_compile_must, ret, cleanup);
+    COMPILE_ARRAY_GOTO(ctx, action_p->output.exts, action->output.exts, options, u, lys_compile_ext, ret, cleanup);
+    LY_LIST_FOR(action_p->output.data, child_p) {
+        LY_CHECK_RET(lys_compile_node(ctx, child_p, options & LYSC_OPT_RPC_OUTPUT, (struct lysc_node*)action, uses_status));
+    }
+
+cleanup:
+    return ret;
+}
+
+/**
  * @brief Compile parsed container node information.
  * @param[in] ctx Compile context
  * @param[in] node_p Parsed container node.
@@ -3033,8 +3145,8 @@
     }
 
     COMPILE_ARRAY_GOTO(ctx, cont_p->musts, cont->musts, options, u, lys_compile_must, ret, done);
-    //COMPILE_ARRAY_GOTO(ctx, cont_p->actions, cont->actions, options, u, lys_compile_action, ret, done);
-    //COMPILE_ARRAY_GOTO(ctx, cont_p->notifs, cont->notifs, options, u, lys_compile_notif, ret, done);
+    COMPILE_ARRAY1_GOTO(ctx, cont_p->actions, cont->actions, node, options, u, lys_compile_action, 0, ret, done);
+    // TODO COMPILE_ARRAY1_GOTO(ctx, cont_p->notifs, cont->notifs, node, options, u, lys_compile_notif, 0, ret, done);
 
 done:
     return ret;
@@ -3203,6 +3315,7 @@
     size_t len;
     unsigned int v;
     int config;
+    uint16_t flags;
 
     for (v = 0; v < LY_ARRAY_SIZE(uniques); ++v) {
         config = -1;
@@ -3221,16 +3334,23 @@
 
             /* unique node must be present */
             LY_ARRAY_NEW_RET(ctx->ctx, *unique, key, LY_EMEM);
-            ret = lys_resolve_schema_nodeid(ctx, keystr, len, (struct lysc_node*)list, context_module, LYS_LEAF, 0, (const struct lysc_node**)key);
+            ret = lys_resolve_schema_nodeid(ctx, keystr, len, (struct lysc_node*)list, context_module, LYS_LEAF, 0,
+                                            (const struct lysc_node**)key, &flags);
             if (ret != LY_SUCCESS) {
                 if (ret == LY_EDENIED) {
                     LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
-                           "Unique's descendant-schema-nodeid \"%.*s\" refers to a %s node instead of a leaf.",
+                           "Unique's descendant-schema-nodeid \"%.*s\" refers to %s node instead of a leaf.",
                            len, keystr, lys_nodetype2str((*key)->nodetype));
                 }
                 return LY_EVALID;
+            } else if (flags) {
+                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+                       "Unique's descendant-schema-nodeid \"%.*s\" refers into %s node.",
+                       len, keystr, flags & LYSC_OPT_NOTIFICATION ? "Notification" : "RPC/action");
+                return LY_EVALID;
             }
 
+
             /* all referenced leafs must be of the same config type */
             if (config != -1 && ((((*key)->flags & LYS_CONFIG_W) && config == 0) || (((*key)->flags & LYS_CONFIG_R) && config == 1))) {
                 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
@@ -3373,8 +3493,8 @@
         LY_CHECK_RET(lys_compile_node_list_unique(ctx, list->module, list_p->uniques, list));
     }
 
-    //COMPILE_ARRAY_GOTO(ctx, list_p->actions, list->actions, options, u, lys_compile_action, ret, done);
-    //COMPILE_ARRAY_GOTO(ctx, list_p->notifs, list->notifs, options, u, lys_compile_notif, ret, done);
+    COMPILE_ARRAY1_GOTO(ctx, list_p->actions, list->actions, node, options, u, lys_compile_action, 0, ret, done);
+    // TODO COMPILE_ARRAY1_GOTO(ctx, list_p->notifs, list->notifs, node, options, u, lys_compile_notif, 0, ret, done);
 
 done:
     return ret;
@@ -3558,52 +3678,6 @@
 }
 
 /**
- * @brief Compile status information of the given node.
- *
- * To simplify getting status of the node, the flags are set following inheritance rules, so all the nodes
- * has the status correctly set during the compilation.
- *
- * @param[in] ctx Compile context
- * @param[in,out] node Compiled node which status is supposed to be resolved. If the status was set explicitely on the node, it is already set in the
- * flags value and we just check the compatibility with the parent's status value.
- * @param[in] parent_flags Flags of the parent node to check/inherit the status value.
- * @return LY_ERR value.
- */
-static LY_ERR
-lys_compile_status(struct lysc_ctx *ctx, struct lysc_node *node, uint16_t parent_flags)
-{
-    /* status - it is not inherited by specification, but it does not make sense to have
-     * current in deprecated or deprecated in obsolete, so we do print warning and inherit status */
-    if (!(node->flags & LYS_STATUS_MASK)) {
-        if (parent_flags & (LYS_STATUS_DEPRC | LYS_STATUS_OBSLT)) {
-            if ((parent_flags & 0x3) != 0x3) {
-                /* do not print the warning when inheriting status from uses - the uses_status value has a special
-                 * combination of bits (0x3) which marks the uses_status value */
-                LOGWRN(ctx->ctx, "Missing explicit \"%s\" status that was already specified in parent, inheriting.",
-                       (parent_flags & LYS_STATUS_DEPRC) ? "deprecated" : "obsolete");
-            }
-            node->flags |= parent_flags & LYS_STATUS_MASK;
-        } else {
-            node->flags |= LYS_STATUS_CURR;
-        }
-    } else if (parent_flags & LYS_STATUS_MASK) {
-        /* check status compatibility with the parent */
-        if ((parent_flags & LYS_STATUS_MASK) > (node->flags & LYS_STATUS_MASK)) {
-            if (node->flags & LYS_STATUS_CURR) {
-                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
-                       "A \"current\" status is in conflict with the parent's \"%s\" status.",
-                       (parent_flags & LYS_STATUS_DEPRC) ? "deprecated" : "obsolete");
-            } else { /* LYS_STATUS_DEPRC */
-                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
-                       "A \"deprecated\" status is in conflict with the parent's \"obsolete\" status.");
-            }
-            return LY_EVALID;
-        }
-    }
-    return LY_SUCCESS;
-}
-
-/**
  * @brief Check uniqness of the node/action/notification name.
  *
  * Data nodes, actions/RPCs and Notifications are stored separately (in distinguish lists) in the schema
@@ -3664,7 +3738,7 @@
     if (node->nodetype == LYS_CASE) {
         children = (struct lysc_node**)&((struct lysc_node_choice*)parent)->cases;
     } else {
-        children = lysc_node_children_p(parent);
+        children = lysc_node_children_p(parent, node->flags);
     }
     if (children) {
         if (!(*children)) {
@@ -3758,7 +3832,7 @@
         cs->sp = node_p;
 
         /* check the case's status (don't need to solve uses_status since case statement cannot be directly in grouping statement */
-        LY_CHECK_RET(lys_compile_status(ctx, (struct lysc_node*)cs, ch->flags), NULL);
+        LY_CHECK_RET(lys_compile_status(ctx, &cs->flags, ch->flags), NULL);
 
         if (node_p->when) {
             LY_ARRAY_NEW_GOTO(ctx->ctx, cs->when, when, ret, error);
@@ -3837,12 +3911,10 @@
     node->flags |= config;
 
     /* inherit the change into the children */
-    LY_LIST_FOR((struct lysc_node*)lysc_node_children(node), child) {
+    LY_LIST_FOR((struct lysc_node*)lysc_node_children(node, 0), child) {
         LY_CHECK_RET(lys_compile_change_config(ctx, child, config_flag, nodeid, 1, refine_flag));
     }
 
-    /* TODO actions and notifications */
-
     return LY_SUCCESS;
 }
 
@@ -3868,7 +3940,7 @@
         }
     } else { /* unset flag */
         for (; parent && parent->nodetype == LYS_CONTAINER && (parent->flags & LYS_MAND_TRUE); parent = parent->parent) {
-            for (iter = (struct lysc_node*)lysc_node_children(parent); iter; iter = iter->next) {
+            for (iter = (struct lysc_node*)lysc_node_children(parent, 0); iter; iter = iter->next) {
                 if (iter->flags & LYS_MAND_TRUE) {
                     /* there is another mandatory node */
                     return;
@@ -3984,10 +4056,12 @@
     struct lysc_node *node;
     struct lysc_when **when, *when_shared;
     int allow_mandatory = 0;
+    uint16_t flags = 0;
+    unsigned int u;
 
     ret = lys_resolve_schema_nodeid(ctx, aug_p->nodeid, 0, parent, parent ? parent->module : ctx->mod_def,
                                                LYS_CONTAINER | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_INOUT | LYS_NOTIF,
-                                               1, (const struct lysc_node**)&target);
+                                               1, (const struct lysc_node**)&target, &flags);
     if (ret != LY_SUCCESS) {
         if (ret == LY_EDENIED) {
             LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
@@ -4031,13 +4105,13 @@
          * here we gets the last created node as last children of our parent */
         if (target->nodetype == LYS_CASE) {
             /* the compiled node is the last child of the target (but it is a case, so we have to be careful and stop) */
-            for (node = (struct lysc_node*)lysc_node_children(target); node->next && node->next->parent == node->parent; node = node->next);
+            for (node = (struct lysc_node*)lysc_node_children(target, flags); node->next && node->next->parent == node->parent; node = node->next);
         } else if (target->nodetype == LYS_CHOICE) {
             /* to pass when statement, we need the last case no matter if it is explicit or implicit case */
             node = ((struct lysc_node_choice*)target)->cases->prev;
         } else {
             /* the compiled node is the last child of the target */
-            node = lysc_node_children(target)->prev;
+            node = lysc_node_children(target, flags)->prev;
         }
 
         if (!allow_mandatory && (node->flags & LYS_CONFIG_W) && (node->flags & LYS_MAND_TRUE)) {
@@ -4063,7 +4137,32 @@
             }
         }
     }
-    /* TODO actions, notifications */
+
+    switch (target->nodetype) {
+    case LYS_CONTAINER:
+        COMPILE_ARRAY1_GOTO(ctx, aug_p->actions, ((struct lysc_node_container*)node)->actions, target,
+                            options, u, lys_compile_action, 0, ret, error);
+        /* TODO notifications */
+        break;
+    case LYS_LIST:
+        COMPILE_ARRAY1_GOTO(ctx, aug_p->actions, ((struct lysc_node_list*)node)->actions, target,
+                            options, u, lys_compile_action, 0, ret, error);
+        /* TODO notifications */
+        break;
+    default:
+        if (aug_p->actions) {
+            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+                   "Invalid augment (%s) of %s node which is not allowed to contain RPC/action node \"%s\".",
+                   aug_p->nodeid, lys_nodetype2str(target->nodetype), aug_p->actions[0].name);
+            return LY_EVALID;
+        }
+        if (aug_p->notifs) {
+            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+                   "Invalid augment (%s) of %s node which is not allowed to contain Notification node \"%s\".",
+                   aug_p->nodeid, lys_nodetype2str(target->nodetype), aug_p->notifs[0].name);
+            return LY_EVALID;
+        }
+    }
 
 error:
     return ret;
@@ -4168,6 +4267,7 @@
     struct lysp_refine *rfn;
     LY_ERR ret = LY_EVALID;
     uint32_t min, max;
+    uint16_t flags;
     struct ly_set refined = {0};
     struct lysc_when **when, *when_shared;
     struct lysp_augment **augments = NULL;
@@ -4250,7 +4350,7 @@
     LY_LIST_FOR(grp->data, node_p) {
         /* 0x3 in uses_status is a special bits combination to be able to detect status flags from uses */
         LY_CHECK_GOTO(lys_compile_node(ctx, node_p, options, parent, (uses_p->flags & LYS_STATUS_MASK) | 0x3), error);
-        child = parent ? lysc_node_children(parent)->prev : ctx->mod->compiled->data->prev;
+        child = parent ? lysc_node_children(parent, options & LYSC_OPT_RPC_MASK)->prev : ctx->mod->compiled->data->prev;
 
         /* some preparation for applying refines */
         if (grp->data == node_p) {
@@ -4277,7 +4377,7 @@
     }
     if (context_node_fake.child) {
         child = context_node_fake.child->prev;
-        context_node_fake.child->prev = parent ? lysc_node_children(parent)->prev : ctx->mod->compiled->data->prev;
+        context_node_fake.child->prev = parent ? lysc_node_children(parent, options & LYSC_OPT_RPC_MASK)->prev : ctx->mod->compiled->data->prev;
     }
 
     /* sort and apply augments */
@@ -4292,7 +4392,7 @@
     /* apply refine */
     LY_ARRAY_FOR(uses_p->refines, struct lysp_refine, rfn) {
         LY_CHECK_GOTO(lys_resolve_schema_nodeid(ctx, rfn->nodeid, 0, (struct lysc_node*)&context_node_fake, ctx->mod,
-                                                0, 0, (const struct lysc_node**)&node),
+                                                0, 0, (const struct lysc_node**)&node, &flags),
                       error);
         ly_set_add(&refined, node, LY_SET_OPT_USEASLIST);
 
@@ -4355,7 +4455,12 @@
 
         /* config */
         if (rfn->flags & LYS_CONFIG_MASK) {
-            LY_CHECK_GOTO(lys_compile_change_config(ctx, node, rfn->flags, rfn->nodeid, 0, 1), error);
+            if (!flags) {
+                LY_CHECK_GOTO(lys_compile_change_config(ctx, node, rfn->flags, rfn->nodeid, 0, 1), error);
+            } else {
+                LOGWRN(ctx->ctx, "Refining config inside %s has no effect (%s).",
+                       flags & LYSC_OPT_NOTIFICATION ? "Notification" : "RPC/action", ctx->path);
+            }
         }
 
         /* mandatory */
@@ -4562,7 +4667,15 @@
     node->flags = node_p->flags & LYS_FLAGS_COMPILED_MASK;
 
     /* config */
-    if (!(node->flags & LYS_CONFIG_MASK)) {
+    if (options & (LYSC_OPT_RPC_INPUT | LYSC_OPT_RPC_OUTPUT)) {
+        /* ignore config statements inside RPC/action data */
+        node->flags &= LYS_CONFIG_MASK;
+        node->flags |= (options & LYSC_OPT_RPC_INPUT) ? LYS_CONFIG_W : LYS_CONFIG_R;
+    } else if (options & LYSC_OPT_NOTIFICATION) {
+        /* ignore config statements inside Notification data */
+        node->flags &= LYS_CONFIG_MASK;
+        node->flags |= LYS_CONFIG_R;
+    } else if (!(node->flags & LYS_CONFIG_MASK)) {
         /* config not explicitely set, inherit it from parent */
         if (parent) {
             node->flags |= parent->flags & LYS_CONFIG_MASK;
@@ -4598,7 +4711,7 @@
     if (!parent || parent->nodetype != LYS_CHOICE) {
         /* in case of choice/case's children, postpone the check to the moment we know if
          * the parent is choice (parent here) or some case (so we have to get its flags to check) */
-        LY_CHECK_GOTO(lys_compile_status(ctx, node, uses_status ? uses_status : (parent ? parent->flags : 0)), error);
+        LY_CHECK_GOTO(lys_compile_status(ctx, &node->flags, uses_status ? uses_status : (parent ? parent->flags : 0)), error);
     }
 
     if (!(options & LYSC_OPT_FREE_SP)) {
@@ -4635,7 +4748,7 @@
             /* the postponed status check of the node and its real parent - in case of implicit case,
              * it directly gets the same status flags as the choice;
              * uses_status cannot be applied here since uses cannot be child statement of choice */
-            LY_CHECK_GOTO(lys_compile_status(ctx, node, cs->flags), error);
+            LY_CHECK_GOTO(lys_compile_status(ctx, &node->flags, cs->flags), error);
             node->parent = (struct lysc_node*)cs;
         } else { /* other than choice */
             node->parent = parent;
@@ -4700,8 +4813,8 @@
         if (!remove_cs) {
             cs = NULL;
         }
-    } else if (lysc_node_children(parent) == node) {
-        *lysc_node_children_p(parent) = node->next;
+    } else if (lysc_node_children(parent, node->flags) == node) {
+        *lysc_node_children_p(parent, node->flags) = node->next;
     }
 
     if (cs) {
@@ -4751,7 +4864,7 @@
     if (node->next) {
         node->next->prev = node->prev;
     } else if (node->nodetype != LYS_CASE) {
-        child = (struct lysc_node*)lysc_node_children(parent);
+        child = (struct lysc_node*)lysc_node_children(parent, node->flags);
         if (child) {
             child->prev = node->prev;
         }
@@ -4778,6 +4891,7 @@
         const char *nodeid;
         struct lysc_node *target;      /* target node of the deviation */
         struct lysp_deviate** deviates;/* sized array of pointers to parsed deviate statements to apply on target */
+        uint16_t flags;                /* target's flags from lys_resolve_schema_nodeid() */
         uint8_t not_supported;         /* flag if deviates contains not-supported deviate */
     } **devs = NULL;
     int i;
@@ -4785,6 +4899,7 @@
     const char *prefix, *name, *nodeid;
     struct lys_module *mod;
     uint32_t min, max;
+    uint16_t flags;
 
     /* get all deviations from the module and all its submodules ... */
     LY_ARRAY_FOR(mod_p->deviations, u) {
@@ -4806,7 +4921,8 @@
         dev = devs_p.objs[u];
 
         /* resolve the target */
-        LY_CHECK_GOTO(lys_resolve_schema_nodeid(ctx, dev->nodeid, 0, NULL, ctx->mod, 0, 1, (const struct lysc_node**)&target), cleanup);
+        LY_CHECK_GOTO(lys_resolve_schema_nodeid(ctx, dev->nodeid, 0, NULL, ctx->mod, 0, 1,
+                                                (const struct lysc_node**)&target, &flags), cleanup);
 
         /* insert into the set of targets with duplicity detection */
         i = ly_set_add(&targets, target, 0);
@@ -4815,6 +4931,7 @@
             devs[i] = calloc(1, sizeof **devs);
             devs[i]->target = target;
             devs[i]->nodeid = dev->nodeid;
+            devs[i]->flags = flags;
         }
         /* add deviates into the deviation's list of deviates */
         for (d = dev->deviates; d; d = d->next) {
@@ -4881,27 +4998,27 @@
     DELFUNC(ctx->ctx, ((TYPE)devs[u]->target)->MEMBER_TRG); \
     ((TYPE)devs[u]->target)->MEMBER_TRG = NULL;
 
-#define DEV_DEL_ARRAY(TYPE, ARRAY, VALMEMBER, VALMEMBER_CMP, DELFUNC_DEREF, DELFUNC, PROPERTY) \
-    DEV_CHECK_PRESENCE(TYPE, 0, ARRAY, "deleting", PROPERTY, d_del->ARRAY[0]VALMEMBER); \
-    LY_ARRAY_FOR(d_del->ARRAY, x) { \
-        LY_ARRAY_FOR(((TYPE)devs[u]->target)->ARRAY, y) { \
-            if (!strcmp(((TYPE)devs[u]->target)->ARRAY[y]VALMEMBER_CMP, d_del->ARRAY[x]VALMEMBER)) { break; } \
+#define DEV_DEL_ARRAY(TYPE, ARRAY_TRG, ARRAY_DEV, VALMEMBER, VALMEMBER_CMP, DELFUNC_DEREF, DELFUNC, PROPERTY) \
+    DEV_CHECK_PRESENCE(TYPE, 0, ARRAY_TRG, "deleting", PROPERTY, d_del->ARRAY_DEV[0]VALMEMBER); \
+    LY_ARRAY_FOR(d_del->ARRAY_DEV, x) { \
+        LY_ARRAY_FOR(((TYPE)devs[u]->target)->ARRAY_TRG, y) { \
+            if (!strcmp(((TYPE)devs[u]->target)->ARRAY_TRG[y]VALMEMBER_CMP, d_del->ARRAY_DEV[x]VALMEMBER)) { break; } \
         } \
-        if (y == LY_ARRAY_SIZE(((TYPE)devs[u]->target)->ARRAY)) { \
+        if (y == LY_ARRAY_SIZE(((TYPE)devs[u]->target)->ARRAY_TRG)) { \
             LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
                    "Invalid deviation (%s) deleting \"%s\" property \"%s\" which does not match any of the target's property values.", \
-                   devs[u]->nodeid, PROPERTY, d_del->ARRAY[x]VALMEMBER); \
+                   devs[u]->nodeid, PROPERTY, d_del->ARRAY_DEV[x]VALMEMBER); \
             goto cleanup; \
         } \
-        LY_ARRAY_DECREMENT(((TYPE)devs[u]->target)->ARRAY); \
-        DELFUNC(ctx->ctx, DELFUNC_DEREF((TYPE)devs[u]->target)->ARRAY[y]); \
-        memmove(&((TYPE)devs[u]->target)->ARRAY[y], \
-                &((TYPE)devs[u]->target)->ARRAY[y + 1], \
-                (LY_ARRAY_SIZE(((TYPE)devs[u]->target)->ARRAY) - y) * (sizeof *((TYPE)devs[u]->target)->ARRAY)); \
+        LY_ARRAY_DECREMENT(((TYPE)devs[u]->target)->ARRAY_TRG); \
+        DELFUNC(ctx->ctx, DELFUNC_DEREF((TYPE)devs[u]->target)->ARRAY_TRG[y]); \
+        memmove(&((TYPE)devs[u]->target)->ARRAY_TRG[y], \
+                &((TYPE)devs[u]->target)->ARRAY_TRG[y + 1], \
+                (LY_ARRAY_SIZE(((TYPE)devs[u]->target)->ARRAY_TRG) - y) * (sizeof *((TYPE)devs[u]->target)->ARRAY_TRG)); \
     } \
-    if (!LY_ARRAY_SIZE(((TYPE)devs[u]->target)->ARRAY)) { \
-        LY_ARRAY_FREE(((TYPE)devs[u]->target)->ARRAY); \
-        ((TYPE)devs[u]->target)->ARRAY = NULL; \
+    if (!LY_ARRAY_SIZE(((TYPE)devs[u]->target)->ARRAY_TRG)) { \
+        LY_ARRAY_FREE(((TYPE)devs[u]->target)->ARRAY_TRG); \
+        ((TYPE)devs[u]->target)->ARRAY_TRG = NULL; \
     }
 
     /* apply deviations */
@@ -4950,8 +5067,19 @@
                                            options, x, lys_compile_must, ret, cleanup);
                         break;
                     case LYS_NOTIF:
-                    case LYS_INOUT:
                         /* TODO */
+                        break;
+                    case LYS_ACTION:
+                        if (devs[u]->flags & LYSC_OPT_RPC_INPUT) {
+                            COMPILE_ARRAY_GOTO(ctx, d_add->musts, ((struct lysc_action*)devs[u]->target)->input.musts,
+                                               options, x, lys_compile_must, ret, cleanup);
+                            break;
+                        } else  if (devs[u]->flags & LYSC_OPT_RPC_OUTPUT) {
+                            COMPILE_ARRAY_GOTO(ctx, d_add->musts, ((struct lysc_action*)devs[u]->target)->output.musts,
+                                               options, x, lys_compile_must, ret, cleanup);
+                            break;
+                        }
+                        /* fall through */
                     default:
                         LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
                                devs[u]->nodeid, lys_nodetype2str(devs[u]->target->nodetype), "add", "must");
@@ -5024,6 +5152,10 @@
                                lys_nodetype2str(devs[u]->target->nodetype), "add", "config");
                         goto cleanup;
                     }
+                    if (devs[u]->flags) {
+                        LOGWRN(ctx->ctx, "Deviating config inside %s has no effect (%s).",
+                               devs[u]->flags & LYSC_OPT_NOTIFICATION ? "Notification" : "RPC/action", devs[u]->nodeid);
+                    }
                     if (devs[u]->target->flags & LYS_SET_CONFIG) {
                         LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
                                "Invalid deviation (%s) adding \"config\" property which already exists (with value \"config %s\").",
@@ -5096,16 +5228,25 @@
                     switch (devs[u]->target->nodetype) {
                     case LYS_CONTAINER:
                     case LYS_LIST:
-                        DEV_DEL_ARRAY(struct lysc_node_container*, musts, .arg, .cond->expr, &, lysc_must_free, "must");
+                        DEV_DEL_ARRAY(struct lysc_node_container*, musts, musts, .arg, .cond->expr, &, lysc_must_free, "must");
                         break;
                     case LYS_LEAF:
                     case LYS_LEAFLIST:
                     case LYS_ANYDATA:
-                        DEV_DEL_ARRAY(struct lysc_node_leaf*, musts, .arg, .cond->expr, &, lysc_must_free, "must");
+                        DEV_DEL_ARRAY(struct lysc_node_leaf*, musts, musts, .arg, .cond->expr, &, lysc_must_free, "must");
                         break;
                     case LYS_NOTIF:
-                    case LYS_INOUT:
                         /* TODO */
+                        break;
+                    case LYS_ACTION:
+                        if (devs[u]->flags & LYSC_OPT_RPC_INPUT) {
+                            DEV_DEL_ARRAY(struct lysc_action*, input.musts, musts, .arg, .cond->expr, &, lysc_must_free, "must");
+                            break;
+                        } else  if (devs[u]->flags & LYSC_OPT_RPC_OUTPUT) {
+                            DEV_DEL_ARRAY(struct lysc_action*, output.musts, musts, .arg, .cond->expr, &, lysc_must_free, "must");
+                            break;
+                        }
+                        /* fall through */
                     default:
                         LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NODETYPE,
                                devs[u]->nodeid, lys_nodetype2str(devs[u]->target->nodetype), "delete", "must");
@@ -5169,7 +5310,7 @@
                         devs[u]->target->flags &= ~LYS_SET_DFLT;
                         break;
                     case LYS_LEAFLIST:
-                        DEV_DEL_ARRAY(struct lysc_node_leaflist*, dflts, , , , lydict_remove, "default");
+                        DEV_DEL_ARRAY(struct lysc_node_leaflist*, dflts, dflts, , , , lydict_remove, "default");
                         if (!((struct lysc_node_leaflist*)devs[u]->target)->dflts) {
                             devs[u]->target->flags &= ~LYS_SET_DFLT;
                         }
@@ -5491,8 +5632,8 @@
         LY_CHECK_GOTO(ret, error);
     }
 
-    //COMPILE_ARRAY_GOTO(ctx, sp->rpcs, mod_c->rpcs, options, u, lys_compile_action, ret, error);
-    //COMPILE_ARRAY_GOTO(ctx, sp->notifs, mod_c->notifs, options, u, lys_compile_notif, ret, error);
+    COMPILE_ARRAY1_GOTO(&ctx, sp->rpcs, mod_c->rpcs, NULL, options, u, lys_compile_action, 0, ret, error);
+    // TODO COMPILE_ARRAY1_GOTO(&ctx, sp->notifs, mod_c->notifs, NULL, options, u, lys_compile_notif, 0, ret, error);
 
     /* augments - sort first to cover augments augmenting other augments */
     ret = lys_compile_augment_sort(&ctx, sp->augments, sp->includes, &augments);
diff --git a/src/tree_schema_free.c b/src/tree_schema_free.c
index 559b635..a17694a 100644
--- a/src/tree_schema_free.c
+++ b/src/tree_schema_free.c
@@ -194,8 +194,8 @@
     FREE_STRINGS(ctx, action->iffeatures);
     FREE_ARRAY(ctx, action->typedefs, lysp_tpdf_free);
     FREE_ARRAY(ctx, action->groupings, lysp_grp_free);
-    FREE_MEMBER(ctx, action->input, lysp_action_inout_free);
-    FREE_MEMBER(ctx, action->output, lysp_action_inout_free);
+    lysp_action_inout_free(ctx, &action->input);
+    lysp_action_inout_free(ctx, &action->output);
     FREE_ARRAY(ctx, action->exts, lysp_ext_instance_free);
 }
 
@@ -629,6 +629,32 @@
     free(type);
 }
 
+void
+lysc_action_free(struct ly_ctx *ctx, struct lysc_action *action)
+{
+    struct lysc_node *child, *child_next;
+
+    FREE_STRING(ctx, action->name);
+    FREE_STRING(ctx, action->dsc);
+    FREE_STRING(ctx, action->ref);
+    FREE_ARRAY(ctx, action->iffeatures, lysc_iffeature_free);
+    FREE_ARRAY(ctx, action->exts, lysc_ext_instance_free);
+
+    /* input */
+    FREE_ARRAY(ctx, action->input.exts, lysc_ext_instance_free);
+    FREE_ARRAY(ctx, action->input.musts, lysc_must_free);
+    LY_LIST_FOR_SAFE(action->input.data, child_next, child) {
+        lysc_node_free(ctx, child);
+    }
+
+    /* output */
+    FREE_ARRAY(ctx, action->output.exts, lysc_ext_instance_free);
+    FREE_ARRAY(ctx, action->output.musts, lysc_must_free);
+    LY_LIST_FOR_SAFE(action->output.data, child_next, child) {
+        lysc_node_free(ctx, child);
+    }
+}
+
 static void
 lysc_node_container_free(struct ly_ctx *ctx, struct lysc_node_container *node)
 {
@@ -638,8 +664,9 @@
         lysc_node_free(ctx, child);
     }
     FREE_ARRAY(ctx, node->musts, lysc_must_free);
+    FREE_ARRAY(ctx, node->actions, lysc_action_free);
 
-    /* TODO actions, notifs */
+    /* TODO notifs */
 }
 
 static void
@@ -686,7 +713,9 @@
     }
     LY_ARRAY_FREE(node->uniques);
 
-    /* TODO actions, notifs */
+    FREE_ARRAY(ctx, node->actions, lysc_action_free);
+
+    /* TODO notifs */
 }
 
 static void
@@ -768,6 +797,8 @@
     LY_LIST_FOR_SAFE(module->data, node_next, node) {
         lysc_node_free(ctx, node);
     }
+    FREE_ARRAY(ctx, module->rpcs, lysc_action_free);
+    /* TODO notifications */
 
     FREE_ARRAY(ctx, module->exts, lysc_ext_instance_free);
 
diff --git a/src/tree_schema_helpers.c b/src/tree_schema_helpers.c
index 0295995..6b89cb3 100644
--- a/src/tree_schema_helpers.c
+++ b/src/tree_schema_helpers.c
@@ -86,17 +86,21 @@
 
 LY_ERR
 lys_resolve_schema_nodeid(struct lysc_ctx *ctx, const char *nodeid, size_t nodeid_len, const struct lysc_node *context_node,
-                          const struct lys_module *context_module, int nodetype, int implement, const struct lysc_node **target)
+                          const struct lys_module *context_module, int nodetype, int implement,
+                          const struct lysc_node **target, uint16_t *result_flag)
 {
     LY_ERR ret = LY_EVALID;
     const char *name, *prefix, *id;
     size_t name_len, prefix_len;
     const struct lys_module *mod;
     const char *nodeid_type;
+    int getnext_extra_flag = 0;
 
     assert(nodeid);
     assert(target);
+    assert(result_flag);
     *target = NULL;
+    *result_flag = 0;
 
     id = nodeid;
 
@@ -139,11 +143,27 @@
             /* make the module implemented */
             ly_ctx_module_implement_internal(ctx->ctx, (struct lys_module*)mod, 2);
         }
-        context_node = lys_child(context_node, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE);
-        if (!context_node) {
-            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
-                   "Invalid %s-schema-nodeid value \"%.*s\" - target node not found.", nodeid_type, id - nodeid, nodeid);
-            return LY_ENOTFOUND;
+        if (context_node && context_node->nodetype == LYS_ACTION) {
+            /* move through input/output manually */
+            if (!strncmp("input", name, name_len)) {
+                (*result_flag) |= LYSC_OPT_RPC_INPUT;
+            } else if (!strncmp("input", name, name_len)) {
+                (*result_flag) |= LYSC_OPT_RPC_OUTPUT;
+                getnext_extra_flag = LYS_GETNEXT_OUTPUT;
+            }
+        } else {
+            context_node = lys_child(context_node, mod, name, name_len, 0,
+                                     getnext_extra_flag | LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE);
+            if (!context_node) {
+                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+                       "Invalid %s-schema-nodeid value \"%.*s\" - target node not found.", nodeid_type, id - nodeid, nodeid);
+                return LY_ENOTFOUND;
+            }
+            getnext_extra_flag = 0;
+
+            if (context_node->nodetype == LYS_NOTIF) {
+                (*result_flag) |= LYSC_OPT_NOTIFICATION;
+            }
         }
         if (!*id || (nodeid_len && ((size_t)(id - nodeid) >= nodeid_len))) {
             break;
@@ -1127,7 +1147,7 @@
 }
 
 struct lysc_node **
-lysc_node_children_p(const struct lysc_node *node)
+lysc_node_children_p(const struct lysc_node *node, uint16_t flags)
 {
     assert(node);
     switch (node->nodetype) {
@@ -1143,22 +1163,24 @@
         return &((struct lysc_node_case*)node)->child;
     case LYS_LIST:
         return &((struct lysc_node_list*)node)->child;
-/* TODO
-    case LYS_INOUT:
-        return &((struct lysc_action_inout*)node)->child;
-    case LYS_NOTIF:
-        return &((struct lysc_notif*)node)->child;
-*/
+    case LYS_ACTION:
+        if (flags & LYS_CONFIG_R) {
+            return &((struct lysc_action*)node)->output.data;
+        } else {
+            /* LYS_CONFIG_W, but also the default case */
+            return &((struct lysc_action*)node)->input.data;
+        }
+    /* TODO Notification */
     default:
         return NULL;
     }
 }
 
 API const struct lysc_node *
-lysc_node_children(const struct lysc_node *node)
+lysc_node_children(const struct lysc_node *node, uint16_t flags)
 {
     struct lysc_node **children;
-    children = lysc_node_children_p((struct lysc_node*)node);
+    children = lysc_node_children_p((struct lysc_node*)node, flags);
     if (children) {
         return *children;
     } else {
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index c2ddf7d..792ce51 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -154,8 +154,12 @@
  *
  * @{
  */
-#define LYSC_OPT_FREE_SP 1           /**< Free the input printable schema */
-#define LYSC_OPT_INTERNAL 2          /**< Internal compilation caused by dependency */
+#define LYSC_OPT_RPC_INPUT  LYS_CONFIG_W       /**< Internal option when compiling schema tree of RPC/action input */
+#define LYSC_OPT_RPC_OUTPUT LYS_CONFIG_R       /**< Internal option when compiling schema tree of RPC/action output */
+#define LYSC_OPT_RPC_MASK   LYS_CONFIG_MASK
+#define LYSC_OPT_FREE_SP    0x04               /**< Free the input printable schema */
+#define LYSC_OPT_INTERNAL   0x08               /**< Internal compilation caused by dependency */
+#define LYSC_OPT_NOTIFICATION 0x10             /**< Internal option when compiling schema tree of Notification */
 /** @} scflags */
 
 /**
@@ -200,9 +204,10 @@
  *
  * Decides the node's type and in case it has a children list, returns its address.
  * @param[in] node Node to check.
+ * @param[in] flags Config flag to distinguish input (LYS_CONFIG_W) and output (LYS_CONFIG_R) data in case of RPC/action node.
  * @return Address of the node's child member if any, NULL otherwise.
  */
-struct lysc_node **lysc_node_children_p(const struct lysc_node *node);
+struct lysc_node **lysc_node_children_p(const struct lysc_node *node, uint16_t flags);
 
 /**
  * @brief Get the covering schema module structure for the given parsed module structure.
@@ -280,11 +285,15 @@
  * the given nodetype, LY_EDENIED is returned (and target is provided), but no error message is printed.
  * The value can be even an ORed value to allow multiple nodetypes.
  * @param[in] implement Flag if the modules mentioned in the nodeid are supposed to be made implemented.
- * @param[out] target Found target node if any.
+ * @param[out] target Found target node if any. In case of RPC/action input/output node, LYS_ACTION node is actually returned
+ * since the input/output has not a standalone node structure and it is part of ::lysc_action which is better compatible with ::lysc_node.
+ * @param[out] result_flag Output parameter to announce if the schema nodeid goes through the action's input/output or a Notification.
+ * The LYSC_OPT_RPC_INPUT, LYSC_OPT_RPC_OUTPUT and LYSC_OPT_NOTIFICATION are used as flags.
  * @return LY_ERR values - LY_ENOTFOUND, LY_EVALID, LY_EDENIED or LY_SUCCESS.
  */
 LY_ERR lys_resolve_schema_nodeid(struct lysc_ctx *ctx, const char *nodeid, size_t nodeid_len, const struct lysc_node *context_node,
-                                 const struct lys_module *context_module, int nodetype, int implement, const struct lysc_node **target);
+                                 const struct lys_module *context_module, int nodetype, int implement,
+                                 const struct lysc_node **target, uint16_t *result_flag);
 
 /**
  * @brief Find the module referenced by prefix in the provided mod.
diff --git a/tests/src/CMakeLists.txt b/tests/src/CMakeLists.txt
index 81753dc..9657398 100644
--- a/tests/src/CMakeLists.txt
+++ b/tests/src/CMakeLists.txt
@@ -5,6 +5,7 @@
     src_hash_table
     src_xml
     src_parser_yang
+    src_tree_schema
     src_tree_schema_compile
     src_tree_schema_helpers)
 set(local_tests_wraps
@@ -15,6 +16,7 @@
     " "
     " "
     " "
+    " "
     " ")
 set(tests ${tests} ${local_tests} PARENT_SCOPE)
 set(tests_wraps ${tests_wraps} ${local_tests_wraps} PARENT_SCOPE)
diff --git a/tests/src/test_tree_schema_compile.c b/tests/src/test_tree_schema_compile.c
index 3f516f1..babfd49 100644
--- a/tests/src/test_tree_schema_compile.c
+++ b/tests/src/test_tree_schema_compile.c
@@ -645,7 +645,7 @@
 
     assert_null(lys_parse_mem(ctx, "module gg {namespace urn:gg;prefix gg;"
                               "list l {key x; unique y;leaf x {type string;} leaf-list y {type string;}}}", LYS_IN_YANG));
-    logbuf_assert("Unique's descendant-schema-nodeid \"y\" refers to a leaf-list node instead of a leaf.");
+    logbuf_assert("Unique's descendant-schema-nodeid \"y\" refers to leaf-list node instead of a leaf.");
 
     assert_null(lys_parse_mem(ctx, "module hh {namespace urn:hh;prefix hh;"
                               "list l {key x; unique \"x y\";leaf x {type string;} leaf y {config false; type string;}}}", LYS_IN_YANG));
@@ -1730,7 +1730,7 @@
                                         "container default-address{leaf ifname{type leafref{ path \"../../interface/name\";}}"
                                           "leaf address {type leafref{ path \"../../interface[  name = current()/../ifname ]/address/ip\";}}}}",
                                         LYS_IN_YANG));
-    type = ((struct lysc_node_leaf*)(*lysc_node_children_p(mod->compiled->data->prev))->prev)->type;
+    type = ((struct lysc_node_leaf*)(*lysc_node_children_p(mod->compiled->data->prev, 0))->prev)->type;
     assert_non_null(type);
     assert_int_equal(1, type->refcount);
     assert_int_equal(LY_TYPE_LEAFREF, type->basetype);
@@ -2194,9 +2194,9 @@
     assert_non_null(mod = lys_parse_mem(ctx, "module d {namespace urn:d;prefix d; grouping grp {container g;}"
                                         "container top {uses grp {augment g {leaf x {type int8;}}}}}", LYS_IN_YANG));
     assert_non_null(mod->compiled->data);
-    assert_non_null(child = lysc_node_children(mod->compiled->data));
+    assert_non_null(child = lysc_node_children(mod->compiled->data, 0));
     assert_string_equal("g", child->name);
-    assert_non_null(child = lysc_node_children(child));
+    assert_non_null(child = lysc_node_children(child, 0));
     assert_string_equal("x", child->name);
 
     /* invalid */
@@ -2409,11 +2409,11 @@
     assert_non_null(ly_ctx_get_module_implemented(ctx, "d"));
     assert_non_null(node = mod->compiled->data);
     assert_string_equal(node->name, "top");
-    assert_non_null(node = lysc_node_children(node));
+    assert_non_null(node = lysc_node_children(node, 0));
     assert_string_equal(node->name, "a");
     assert_non_null(node = node->next);
     assert_string_equal(node->name, "c");
-    assert_non_null(node = lysc_node_children(node));
+    assert_non_null(node = lysc_node_children(node, 0));
     assert_string_equal(node->name, "c");
     assert_non_null(node = node->next);
     assert_string_equal(node->name, "d");
@@ -2447,7 +2447,7 @@
     assert_non_null((mod = lys_parse_mem(ctx, "module f {namespace urn:f;prefix f;grouping g {leaf a {type string;}}"
                                          "container c;"
                                          "augment /c {uses g;}}", LYS_IN_YANG)));
-    assert_non_null(node = lysc_node_children(mod->compiled->data));
+    assert_non_null(node = lysc_node_children(mod->compiled->data, 0));
     assert_string_equal(node->name, "a");
 
     ly_ctx_set_module_imp_clb(ctx, test_imp_clb, "submodule gsub {belongs-to g {prefix g;}"
@@ -2535,7 +2535,7 @@
     assert_non_null((mod = ly_ctx_get_module_implemented(ctx, "a")));
     assert_non_null(node = mod->compiled->data);
     assert_string_equal(node->name, "top");
-    assert_non_null(node = lysc_node_children(node));
+    assert_non_null(node = lysc_node_children(node, 0));
     assert_string_equal(node->name, "a");
     assert_non_null(node = node->next);
     assert_string_equal(node->name, "c");
@@ -2677,7 +2677,7 @@
     assert_non_null(node = node->next);
     assert_string_equal("top", node->name);
     assert_true(node->flags & LYS_CONFIG_R);
-    assert_non_null(node = lysc_node_children(node));
+    assert_non_null(node = lysc_node_children(node, 0));
     assert_string_equal("x", node->name);
     assert_true(node->flags & LYS_CONFIG_R);
     assert_non_null(node = node->next);
@@ -2694,7 +2694,7 @@
     assert_non_null(node = node->next);
     assert_string_equal("top", node->name);
     assert_true(node->flags & LYS_CONFIG_W);
-    assert_non_null(node = lysc_node_children(node));
+    assert_non_null(node = lysc_node_children(node, 0));
     assert_string_equal("x", node->name);
     assert_true(node->flags & LYS_CONFIG_W);
 
@@ -2706,11 +2706,11 @@
     assert_non_null(node = mod->compiled->data);
     assert_string_equal("a", node->name);
     assert_true((node->flags & LYS_MAND_MASK) == LYS_MAND_TRUE);
-    assert_true((lysc_node_children(node)->flags & LYS_MAND_MASK) == LYS_MAND_TRUE);
+    assert_true((lysc_node_children(node, 0)->flags & LYS_MAND_MASK) == LYS_MAND_TRUE);
     assert_non_null(node = node->next);
     assert_string_equal("b", node->name);
     assert_false(node->flags & LYS_MAND_MASK); /* just unset on container */
-    assert_true((lysc_node_children(node)->flags & LYS_MAND_MASK) == LYS_MAND_FALSE);
+    assert_true((lysc_node_children(node, 0)->flags & LYS_MAND_MASK) == LYS_MAND_FALSE);
 
     assert_non_null(mod = lys_parse_mem(ctx, "module n {yang-version 1.1; namespace urn:n;prefix n;"
                                         "leaf a {default test; type string;}"