private static Expression CreateBindingExpression(Type type, ReadOnlyMemory <char> expr, ParameterExpression scope, ParameterExpression instance)
        {
            Expression body = Expression.Convert(instance, type);

            var currType = type;

            var pos   = 0;
            var depth = 0;
            var delim = ".".AsMemory();

            while (expr.TryReadPart(delim, out ReadOnlyMemory <char> member, ref pos))
            {
                try
                {
                    if (member.IndexOf('(') >= 0)
                    {
                        throw new BindingExpressionException(
                                  $"Calling methods in '{expr}' is not allowed in binding expressions, use a filter instead.",
                                  member.ToString(), expr.ToString());
                    }

                    var indexerPos = member.IndexOf('[');
                    if (indexerPos >= 0)
                    {
                        var prop    = member.LeftPart('[');
                        var indexer = member.RightPart('[');
                        indexer.Span.ParseJsExpression(out var token);

                        if (token is JsCallExpression)
                        {
                            throw new BindingExpressionException($"Only constant binding expressions are supported: '{expr}'",
                                                                 member.ToString(), expr.ToString());
                        }

                        var value = JsToken.UnwrapValue(token);

                        var valueExpr = value == null
                            ? (Expression)Expression.Call(
                            typeof(SharpPageUtils).GetStaticMethod(nameof(EvaluateBinding)),
                            scope,
                            Expression.Constant(token))
                            : Expression.Constant(value);

                        if (currType == typeof(string))
                        {
                            body = CreateStringIndexExpression(body, token, scope, valueExpr, ref currType);
                        }
                        else if (currType.IsArray)
                        {
                            if (token != null)
                            {
                                var evalAsInt = typeof(SharpPageUtils).GetStaticMethod(nameof(EvaluateBindingAs))
                                                .MakeGenericMethod(typeof(int));
                                body = Expression.ArrayIndex(body,
                                                             Expression.Call(evalAsInt, scope, Expression.Constant(token)));
                            }
                            else
                            {
                                body = Expression.ArrayIndex(body, valueExpr);
                            }
                        }
                        else if (depth == 0)
                        {
                            var pi = AssertProperty(currType, "Item", expr);
                            currType = pi.PropertyType;

                            if (token != null)
                            {
                                var indexType = pi.GetGetMethod()?.GetParameters().FirstOrDefault()?.ParameterType;
                                if (indexType != typeof(object))
                                {
                                    var evalAsInt = typeof(SharpPageUtils).GetStaticMethod(nameof(EvaluateBindingAs))
                                                    .MakeGenericMethod(indexType);
                                    valueExpr = Expression.Call(evalAsInt, scope, Expression.Constant(token));
                                }
                            }

                            body = Expression.Property(body, "Item", valueExpr);
                        }
                        else
                        {
                            var pi = AssertProperty(currType, prop.ToString(), expr);
                            currType = pi.PropertyType;
                            body     = Expression.PropertyOrField(body, prop.ToString());

                            if (currType == typeof(string))
                            {
                                body = CreateStringIndexExpression(body, token, scope, valueExpr, ref currType);
                            }
                            else
                            {
                                var indexMethod = currType.GetMethod("get_Item", new[] { value.GetType() });
                                body     = Expression.Call(body, indexMethod, valueExpr);
                                currType = indexMethod.ReturnType;
                            }
                        }
                    }
                    else
                    {
                        if (depth >= 1)
                        {
                            var memberName = member.ToString();
                            if (typeof(IDictionary).IsAssignableFrom(currType))
                            {
                                var pi = AssertProperty(currType, "Item", expr);
                                currType = pi.PropertyType;
                                body     = Expression.Property(body, "Item", Expression.Constant(memberName));
                            }
                            else
                            {
                                body = Expression.PropertyOrField(body, memberName);
                                var pi = currType.GetProperty(memberName);
                                if (pi != null)
                                {
                                    currType = pi.PropertyType;
                                }
                                else
                                {
                                    var fi = currType.GetField(memberName);
                                    if (fi != null)
                                    {
                                        currType = fi.FieldType;
                                    }
                                }
                            }
                        }
                    }

                    depth++;
                }
                catch (BindingExpressionException)
                {
                    throw;
                }
                catch (Exception e)
                {
                    throw new BindingExpressionException($"Could not compile '{member}' from expression '{expr}'",
                                                         member.ToString(), expr.ToString(), e);
                }
            }
            return(body);
        }