private static ExpressionNode ParseAgainstModel(Type modelType, string expression, ExpressionScope expressionScope, IMemberLocator memberLocator, SourceLocation location)
        {
            var dotIndex = expression.IndexOf('.');
            if (dotIndex >= 0)
            {
				var subModel = ParseAgainstModel(modelType, expression.Substring(0, dotIndex), expressionScope, memberLocator, location.SetLength(dotIndex));
                return SyntaxTreeExpression.SubModel(
                    subModel,
                    ParseAgainstModel(subModel.ResultType, expression.Substring(dotIndex + 1), ExpressionScope.CurrentModelOnStack, memberLocator, location.MoveIndex(dotIndex + 1)),
					location
                );
            }

            if (expression.EndsWith("()"))
            {
                var func = memberLocator.FindMethod(modelType, expression.Substring(0, expression.Length - 2));
                if (func != null) return SyntaxTreeExpression.Function(modelType, func.Name, location, expressionScope);
            }

            var prop = memberLocator.FindProperty(modelType, expression);
		    if (prop != null)
		        return SyntaxTreeExpression.Property(modelType, prop.Name, location, expressionScope);

            var field = memberLocator.FindField(modelType, expression);
		    if (field != null)
		        return SyntaxTreeExpression.Field(modelType, field.Name, location, expressionScope);

            if (IsLateBoundAcceptingType(modelType)) 
				return SyntaxTreeExpression.LateBound(expression, location, memberLocator, false, expressionScope);

            throw new VeilParserException(
                $"Unable to parse model expression '{expression}' againt model '{modelType.Name}'", location);
        }
        public static Func<object, object> GetBinder(object model, string itemName, IMemberLocator memberLocator)
        {
            var binder = LateBoundCache.GetOrAdd(Tuple.Create(model.GetType(), itemName), pair =>
            {
                var type = pair.Item1;
                var name = pair.Item2;

                if (name.EndsWith("()"))
                {
                    var function =
                        memberLocator.FindMethod(type, name.Substring(0, name.Length - 2));
                    if (function != null) return DelegateBuilder.FunctionCall(type, function);
                }

                var property = memberLocator.FindProperty(type, name);
                if (property != null) return DelegateBuilder.Property(type, property);

                var field = memberLocator.FindField(type, name);
                if (field != null) return DelegateBuilder.Field(type, field);

                var dictionaryType = type.GetDictionaryTypeWithKey();
                if (dictionaryType != null) return DelegateBuilder.Dictionary(dictionaryType, name);

                return null;
            });
            return binder;
        }