/// <summary>
        /// Deserializes a Bonsai expression.
        /// </summary>
        /// <param name="expression">Bonsai expression to deserialize.</param>
        /// <returns>Slim expression represented by the given Bonsai.</returns>
        private ExpressionSlim JsonDeserialize(Json.Expression expression)
        {
            if (expression.NodeType == Json.ExpressionType.Null)
            {
                return(null);
            }


            if (expression is not Json.ObjectExpression obj)
            {
                throw new InvalidOperationException("Expected JSON object expression.");
            }

            if (!obj.Members.TryGetValue("Context", out Json.Expression context))
            {
                throw new InvalidOperationException("Context not found.");
            }

            if (!obj.Members.TryGetValue("Expression", out Json.Expression expr))
            {
                throw new InvalidOperationException("Expression not found.");
            }

            if (expr.NodeType == Json.ExpressionType.Null)
            {
                return(null);
            }

            var deserializationState = new DeserializationState(context, _version);

            var visitor = new DeserializerImpl(deserializationState, GetConstantDeserializerDelegate);

            return(visitor.Visit(expr));
        }
        /// <summary>
        /// Deserializes a Bonsai expression.
        /// </summary>
        /// <param name="expression">Bonsai expression to deserialize.</param>
        /// <returns>Slim expression represented by the given Bonsai.</returns>
        public ExpressionSlim Deserialize(Json.Expression expression)
        {
            if (expression == null)
            {
                throw new ArgumentNullException(nameof(expression));
            }

            Json.Expression expr;

            if (_mergeContext && _deserializationState != null)
            {
                expr = expression;
            }
            else
            {
                if (expression.NodeType == Json.ExpressionType.Null)
                {
                    return(null);
                }

                if (expression is not Json.ObjectExpression obj)
                {
                    throw new BonsaiParseException("Expected a JSON object containing the Bonsai representation of an expression.", expression);
                }

                if (!obj.Members.TryGetValue("Context", out Json.Expression context))
                {
                    throw new BonsaiParseException("Expected a JSON object property 'node.Context' containing the context object.", expression);
                }

                if (!obj.Members.TryGetValue("Expression", out expr))
                {
                    throw new BonsaiParseException("Expected a JSON object property 'node.Expression' containing the expression tree.", expression);
                }

                _deserializationState = new DeserializationState(context, _version);
            }

            if (expr.NodeType == Json.ExpressionType.Null)
            {
                return(null);
            }

            var visitor = new DeserializerImpl(_deserializationState, _reduceFactory);

            return(visitor.Visit(expr));
        }