Ejemplo n.º 1
0
        /// <summary>
        /// Creates a pure wrapper for function with 2 and more arguments.
        /// </summary>
        private void createPureWrapperMany(MethodEntity wrapper, string pureName)
        {
            var args = wrapper.GetArgumentTypes(Context);

            var fieldName = string.Format(EntityNames.PureMethodCacheNameTemplate, wrapper.Name);
            var tupleType = FunctionalHelper.CreateTupleType(args);
            var fieldType = typeof(Dictionary <,>).MakeGenericType(tupleType, wrapper.ReturnType);

            CreateField(fieldName, fieldType, true);

            var argGetters = wrapper.Arguments.Select(a => (NodeBase)Expr.Get(a)).ToArray();
            var tupleName  = "<args>";

            wrapper.Body = Expr.Block(
                ScopeKind.FunctionRoot,

                // $tmp = new Tuple<...> $arg1 $arg2 ...
                Expr.Let(tupleName, Expr.New(tupleType, argGetters)),

                // if ($dict == null) $dict = new Dictionary<$tupleType, $valueType> ()
                Expr.If(
                    Expr.Equal(
                        Expr.GetMember(EntityNames.MainTypeName, fieldName),
                        Expr.Null()
                        ),
                    Expr.Block(
                        Expr.SetMember(
                            EntityNames.MainTypeName, fieldName,
                            Expr.New(fieldType)
                            )
                        )
                    ),

                // if(not $dict.ContainsKey key) $dict.Add ($internal arg)
                Expr.If(
                    Expr.Not(
                        Expr.Invoke(
                            Expr.GetMember(EntityNames.MainTypeName, fieldName),
                            "ContainsKey",
                            Expr.Get(tupleName)
                            )
                        ),
                    Expr.Block(
                        Expr.Invoke(
                            Expr.GetMember(EntityNames.MainTypeName, fieldName),
                            "Add",
                            Expr.Get(tupleName),
                            Expr.Invoke(EntityNames.MainTypeName, pureName, argGetters)
                            )
                        )
                    ),

                // $dict[arg]
                Expr.GetIdx(
                    Expr.GetMember(EntityNames.MainTypeName, fieldName),
                    Expr.Get(tupleName)
                    )

                );
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Creates a method without setting argument type info.
        /// </summary>
        private MethodEntity CreateMethodCore(string name, bool isStatic, bool isVirtual, bool prepare, Action <MethodEntity> extraInit = null)
        {
            var me = new MethodEntity(this)
            {
                Name      = name,
                IsStatic  = isStatic,
                IsVirtual = isVirtual,
            };

            Context.UnprocessedMethods.Add(me);

            extraInit?.Invoke(me);

            if (prepare)
            {
                me.PrepareSelf();
                CheckMethod(me);
            }
            else
            {
                Context.UnpreparedTypeContents.Add(me);
            }

            return(me);
        }
Ejemplo n.º 3
0
        public override void ProcessClosures(Context ctx)
        {
            if (MustInferArgTypes)
            {
                var name = Arguments.First(a => a.Type == typeof (UnspecifiedType)).Name;
                error(CompilerMessages.LambdaArgTypeUnknown, name);
            }

            // get evaluated return type
            var retType = _InferredReturnType ?? Body.Resolve(ctx);
            if (retType == typeof(NullType))
                error(CompilerMessages.LambdaReturnTypeUnknown);
            if (retType.IsVoid())
                retType = typeof (void);

            _Method = ctx.Scope.CreateClosureMethod(ctx, Arguments, retType);
            _Method.Body = Body;

            var outerMethod = ctx.CurrentMethod;
            ctx.CurrentMethod = _Method;

            _Method.Body.ProcessClosures(ctx);

            ctx.CurrentMethod = outerMethod;
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Creates a wrapper for the pure method that contains the value cache.
        /// </summary>
        private void CreatePureWrapper(MethodEntity method)
        {
            if (method.ReturnType.IsVoid())
            {
                Context.Error(CompilerMessages.PureFunctionReturnUnit, method.Name);
            }

            var pureName = string.Format(EntityNames.PureMethodNameTemplate, method.Name);
            var pure     = CreateMethod(pureName, method.ReturnTypeSignature, method.Arguments.Values, true);

            pure.Body = method.Body;

            var argCount = method.Arguments != null
                ? method.Arguments.Count
                : method.ArgumentTypes.Length;

            if (argCount >= 8)
            {
                Context.Error(CompilerMessages.PureFunctionTooManyArgs, method.Name);
            }

            if (argCount == 0)
            {
                CreatePureWrapper0(method, pureName);
            }
            else if (argCount == 1)
            {
                CreatePureWrapper1(method, pureName);
            }
            else
            {
                CreatePureWrapperMany(method, pureName);
            }
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Invokes generation of FieldBuilder, MethodBuilder and ConstructorBuilder objects for type members.
        /// </summary>
        public void CheckMethod(MethodEntity method)
        {
            try
            {
                // exception is good
                ResolveMethod(method.Name, method.GetArgumentTypes(Context), true);

                if (this == Context.MainType)
                {
                    Context.Error(CompilerMessages.FunctionRedefinition, method.Name);
                }
                else
                {
                    Context.Error(CompilerMessages.MethodRedefinition, method.Name, Name);
                }
            }
            catch (KeyNotFoundException)
            {
                if (!_methods.ContainsKey(method.Name))
                {
                    _methods.Add(method.Name, new List <MethodEntity> {
                        method
                    });
                }
                else
                {
                    _methods[method.Name].Add(method);
                }
            }
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Creates a pure wrapper for parameterless function.
        /// </summary>
        private void CreatePureWrapper0(MethodEntity wrapper, string pureName)
        {
            var fieldName = string.Format(EntityNames.PureMethodCacheNameTemplate, wrapper.Name);
            var flagName  = string.Format(EntityNames.PureMethodCacheFlagNameTemplate, wrapper.Name);

            CreateField(fieldName, wrapper.ReturnTypeSignature, true);
            CreateField(flagName, typeof(bool), true);

            wrapper.Body = Expr.Block(
                ScopeKind.FunctionRoot,

                // if (not $flag) $cache = $internal (); $flag = true
                Expr.If(
                    Expr.Not(Expr.GetMember(EntityNames.MainTypeName, flagName)),
                    Expr.Block(
                        Expr.SetMember(
                            EntityNames.MainTypeName,
                            fieldName,
                            Expr.Invoke(EntityNames.MainTypeName, pureName)
                            ),
                        Expr.SetMember(EntityNames.MainTypeName, flagName, Expr.True())
                        )
                    ),

                // $cache
                Expr.GetMember(EntityNames.MainTypeName, fieldName)
                );
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Creates a pure wrapper for function with 1 argument.
        /// </summary>
        private void CreatePureWrapper1(MethodEntity wrapper, string pureName)
        {
            var args    = wrapper.GetArgumentTypes(Context);
            var argName = wrapper.Arguments[0].Name;

            var fieldName = string.Format(EntityNames.PureMethodCacheNameTemplate, wrapper.Name);
            var fieldType = typeof(Dictionary <,>).MakeGenericType(args[0], wrapper.ReturnType);

            CreateField(fieldName, fieldType, true);

            wrapper.Body = Expr.Block(
                ScopeKind.FunctionRoot,

                // if ($dict == null) $dict = new Dictionary<$argType, $valueType> ()
                Expr.If(
                    Expr.Equal(
                        Expr.GetMember(EntityNames.MainTypeName, fieldName),
                        Expr.Null()
                        ),
                    Expr.Block(
                        Expr.SetMember(
                            EntityNames.MainTypeName, fieldName,
                            Expr.New(fieldType)
                            )
                        )
                    ),

                // if(not $dict.ContainsKey key) $dict.Add ($internal arg)
                Expr.If(
                    Expr.Not(
                        Expr.Invoke(
                            Expr.GetMember(EntityNames.MainTypeName, fieldName),
                            "ContainsKey",
                            Expr.Get(argName)
                            )
                        ),
                    Expr.Block(
                        Expr.Invoke(
                            Expr.GetMember(EntityNames.MainTypeName, fieldName),
                            "Add",
                            Expr.Get(argName),
                            Expr.Invoke(EntityNames.MainTypeName, pureName, Expr.Get(argName))
                            )
                        )
                    ),

                // $dict[arg]
                Expr.GetIdx(
                    Expr.GetMember(EntityNames.MainTypeName, fieldName),
                    Expr.Get(argName)
                    )
                );
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Invokes generation of FieldBuilder, MethodBuilder and ConstructorBuilder objects for type members.
        /// </summary>
        public void CheckMethod(MethodEntity method)
        {
            try
            {
                // exception is good
                ResolveMethod(method.Name, method.GetArgumentTypes(Context), true);

                if (this == Context.MainType)
                    Context.Error(CompilerMessages.FunctionRedefinition, method.Name);
                else
                    Context.Error(CompilerMessages.MethodRedefinition, method.Name, Name);
            }
            catch (KeyNotFoundException)
            {
                if (!_Methods.ContainsKey(method.Name))
                    _Methods.Add(method.Name, new List<MethodEntity> { method });
                else
                    _Methods[method.Name].Add(method);
            }
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Imports a new method to the given type.
        /// </summary>
        internal void ImportMethod(string name, MethodInfo mi, bool check)
        {
            if (!mi.IsStatic || !mi.IsPublic)
            {
                Context.Error(CompilerMessages.ImportUnsupportedMethod);
            }

            var args = mi.GetParameters().Select(p => new FunctionArgument(p.Name, p.ParameterType, p.ParameterType.IsByRef));
            var me   = new MethodEntity(this)
            {
                Name       = name,
                IsImported = true,
                IsStatic   = true,
                IsVirtual  = false,
                IsVariadic = ReflectionHelper.IsVariadic(mi),
                MethodInfo = mi,
                ReturnType = mi.ReturnType,
                Arguments  = new HashList <FunctionArgument>(args, arg => arg.Name)
            };

            if (check)
            {
                CheckMethod(me);
            }
            else
            {
                if (_methods.ContainsKey(name))
                {
                    _methods[name].Add(me);
                }
                else
                {
                    _methods.Add(name, new List <MethodEntity> {
                        me
                    });
                }
            }
        }
Ejemplo n.º 10
0
        public override void ProcessClosures(Context ctx)
        {
            _Method = ctx.CurrentScope.CreateClosureMethod(ctx, Arguments);
            _Method.Body = Body;

            var methodBackup = ctx.CurrentMethod;
            ctx.CurrentMethod = _Method;

            var scope = _Method.Scope;
            scope.InitializeScope(ctx);
            base.ProcessClosures(ctx);

            // get evaluated return type
            var retType = Body.GetExpressionType(ctx);
            if(retType == typeof(NullType))
                Error(CompilerMessages.LambdaReturnTypeUnknown);

            _Method.ReturnType = retType.IsVoid() ? typeof(void) : retType;
            _Method.PrepareSelf();

            scope.FinalizeScope(ctx);

            ctx.CurrentMethod = methodBackup;
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Imports a new method to the given type.
        /// </summary>
        internal void ImportMethod(string name, MethodInfo mi, bool check)
        {
            if(!mi.IsStatic || !mi.IsPublic)
                Context.Error(CompilerMessages.ImportUnsupportedMethod);

            var args = mi.GetParameters().Select(p => new FunctionArgument(p.Name, p.ParameterType, p.ParameterType.IsByRef));
            var me = new MethodEntity
            {
                Name = name,
                IsImported = true,
                IsStatic = true,
                IsVirtual = false,
                ContainerType = this,
                MethodInfo = mi,
                ReturnType = mi.ReturnType,
                Arguments = new HashList<FunctionArgument>(args, arg => arg.Name)
            };

            if (check)
            {
                _MethodList.Add(me);
            }
            else
            {
                if(_Methods.ContainsKey(name))
                    _Methods[name].Add(me);
                else
                    _Methods.Add(name, new List<MethodEntity> { me });
            }
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Creates a method without setting argument type info.
        /// </summary>
        private MethodEntity createMethodCore(string name, bool isStatic, bool isVirtual, bool prepare, Action<MethodEntity> extraInit = null)
        {
            var me = new MethodEntity(this)
            {
                Name = name,
                IsStatic = isStatic,
                IsVirtual = isVirtual,
            };

            Context.UnprocessedMethods.Add(me);

            if (extraInit != null)
                extraInit(me);

            if (prepare)
            {
                me.PrepareSelf();
                CheckMethod(me);
            }
            else
            {
                Context.UnpreparedTypeContents.Add(me);
            }

            return me;
        }
Ejemplo n.º 13
0
        protected override Type resolve(Context ctx, bool mustReturn)
        {
            if(Identifier == "_")
                error(CompilerMessages.UnderscoreNameUsed);

            // local variable
            var local = Local ?? ctx.Scope.FindLocal(Identifier);
            if (local != null)
            {
                // only local constants are cached
                // because mutable variables could be closured later on
                if (local.IsConstant && local.IsImmutable && ctx.Options.UnrollConstants)
                    _LocalConstant = local;

                return local.Type;
            }

            // static function declared in the script
            try
            {
                var methods = ctx.MainType.ResolveMethodGroup(Identifier);
                if (methods.Length > 1)
                    error(CompilerMessages.FunctionInvocationAmbiguous, Identifier);

                _Method = methods[0];
                return FunctionalHelper.CreateFuncType(_Method.ReturnType, _Method.GetArgumentTypes(ctx));
            }
            catch (KeyNotFoundException) { }

            // algebraic type without a constructor
            var type = ctx.FindType(Identifier);
            if (type != null && type.Kind == TypeEntityKind.TypeLabel)
            {
                try
                {
                    type.ResolveConstructor(new Type[0]);
                    _Type = type;
                    return _Type.TypeInfo;
                }
                catch (KeyNotFoundException) { }
            }

            // global property
            try
            {
                _Property = ctx.ResolveGlobalProperty(Identifier);
                return _Property.PropertyType;
            }
            catch (KeyNotFoundException)
            {
                error(CompilerMessages.IdentifierNotFound, Identifier);
            }

            return typeof (UnitType);
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Creates a pure wrapper for function with 2 and more arguments.
        /// </summary>
        private void createPureWrapperMany(MethodEntity wrapper, string pureName)
        {
            var args = wrapper.GetArgumentTypes(Context);

            var fieldName = string.Format(EntityNames.PureMethodCacheNameTemplate, wrapper.Name);
            var tupleType = FunctionalHelper.CreateTupleType(args);
            var fieldType = typeof(Dictionary<,>).MakeGenericType(tupleType, wrapper.ReturnType);

            CreateField(fieldName, fieldType, true);

            var argGetters = wrapper.Arguments.Select(a => (NodeBase)Expr.Get(a)).ToArray();
            var tupleName = "<args>";

            wrapper.Body = Expr.Block(
                ScopeKind.FunctionRoot,

                // $tmp = new Tuple<...> $arg1 $arg2 ...
                Expr.Let(tupleName, Expr.New(tupleType, argGetters)),

                // if ($dict == null) $dict = new Dictionary<$tupleType, $valueType> ()
                Expr.If(
                    Expr.Equal(
                        Expr.GetMember(EntityNames.MainTypeName, fieldName),
                        Expr.Null()
                    ),
                    Expr.Block(
                        Expr.SetMember(
                            EntityNames.MainTypeName, fieldName,
                            Expr.New(fieldType)
                        )
                    )
                ),

                // if(not $dict.ContainsKey key) $dict.Add ($internal arg)
                Expr.If(
                    Expr.Not(
                        Expr.Invoke(
                            Expr.GetMember(EntityNames.MainTypeName, fieldName),
                            "ContainsKey",
                            Expr.Get(tupleName)
                        )
                    ),
                    Expr.Block(
                        Expr.Invoke(
                            Expr.GetMember(EntityNames.MainTypeName, fieldName),
                            "Add",
                            Expr.Get(tupleName),
                            Expr.Invoke(EntityNames.MainTypeName, pureName, argGetters)
                        )
                    )
                ),

                // $dict[arg]
                Expr.GetIdx(
                    Expr.GetMember(EntityNames.MainTypeName, fieldName),
                    Expr.Get(tupleName)
                )

            );
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Creates a pure wrapper for function with 1 argument.
        /// </summary>
        private void createPureWrapper1(MethodEntity wrapper, string pureName)
        {
            var args = wrapper.GetArgumentTypes(Context);
            var argName = wrapper.Arguments[0].Name;

            var fieldName = string.Format(EntityNames.PureMethodCacheNameTemplate, wrapper.Name);
            var fieldType = typeof(Dictionary<,>).MakeGenericType(args[0], wrapper.ReturnType);

            CreateField(fieldName, fieldType, true);

            wrapper.Body = Expr.Block(
                ScopeKind.FunctionRoot,

                // if ($dict == null) $dict = new Dictionary<$argType, $valueType> ()
                Expr.If(
                    Expr.Equal(
                        Expr.GetMember(EntityNames.MainTypeName, fieldName),
                        Expr.Null()
                    ),
                    Expr.Block(
                        Expr.SetMember(
                            EntityNames.MainTypeName, fieldName,
                            Expr.New(fieldType)
                        )
                    )
                ),

                // if(not $dict.ContainsKey key) $dict.Add ($internal arg)
                Expr.If(
                    Expr.Not(
                        Expr.Invoke(
                            Expr.GetMember(EntityNames.MainTypeName, fieldName),
                            "ContainsKey",
                            Expr.Get(argName)
                        )
                    ),
                    Expr.Block(
                        Expr.Invoke(
                            Expr.GetMember(EntityNames.MainTypeName, fieldName),
                            "Add",
                            Expr.Get(argName),
                            Expr.Invoke(EntityNames.MainTypeName, pureName, Expr.Get(argName))
                        )
                    )
                ),

                // $dict[arg]
                Expr.GetIdx(
                    Expr.GetMember(EntityNames.MainTypeName, fieldName),
                    Expr.Get(argName)
                )
            );
        }
Ejemplo n.º 16
0
        /// <summary>
        /// Creates a wrapper for the pure method that contains the value cache.
        /// </summary>
        private void createPureWrapper(MethodEntity method)
        {
            if (method.ReturnType.IsVoid())
                Context.Error(CompilerMessages.PureFunctionReturnUnit, method.Name);

            var pureName = string.Format(EntityNames.PureMethodNameTemplate, method.Name);
            var pure = CreateMethod(pureName, method.ReturnTypeSignature, method.Arguments.Values, true);
            pure.Body = method.Body;

            var argCount = method.Arguments != null ? method.Arguments.Count : method.ArgumentTypes.Length;

            if (argCount >= 8)
                Context.Error(CompilerMessages.PureFunctionTooManyArgs, method.Name);

            if (argCount == 0)
                createPureWrapper0(method, pureName);
            else if (argCount == 1)
                createPureWrapper1(method, pureName);
            else
                createPureWrapperMany(method, pureName);
        }
Ejemplo n.º 17
0
        protected override Type resolveExpressionType(Context ctx, bool mustReturn = true)
        {
            var local = LocalName ?? ctx.CurrentScope.FindName(Identifier);
            if (local != null)
            {
                // only local constants are cached
                // because mutable variables could be closured later on
                if (local.IsConstant && local.IsImmutable && ctx.Options.UnrollConstants)
                    m_LocalConstant = local;

                return local.Type;
            }

            try
            {
                var methods = ctx.MainType.ResolveMethodGroup(Identifier);
                if (methods.Length > 1)
                    Error(CompilerMessages.FunctionInvocationAmbiguous, Identifier);

                m_Method = methods[0];
                return FunctionalHelper.CreateFuncType(m_Method.ReturnType, m_Method.GetArgumentTypes(ctx));
            }
            catch (KeyNotFoundException) { }

            try
            {
                m_Property = ctx.ResolveGlobalProperty(Identifier);
                return m_Property.PropertyType;
            }
            catch (KeyNotFoundException)
            {
                Error(CompilerMessages.IdentifierNotFound, Identifier);
            }

            return typeof (Unit);
        }
Ejemplo n.º 18
0
        public override void ProcessClosures(Context ctx)
        {
            if(LeftOperand is LambdaNode)
                LeftOperand.ProcessClosures(ctx);

            if (RightOperand is LambdaNode)
                RightOperand.ProcessClosures(ctx);

            var leftType = LeftOperand.GetExpressionType(ctx);

            var rightGetter = RightOperand as GetMemberNode;
            if (!IsLeft && leftType.IsCallableType() && rightGetter != null)
            {
                if (rightGetter.TypeHints.IsEmpty())
                {
                    var returnType = ctx.ResolveMethod(leftType, "Invoke").ReturnType;
                    rightGetter.TypeHints = new List<TypeSignature> {TypeSignature.Parse(returnType.FullName)};
                }
            }

            var rightType = RightOperand.GetExpressionType(ctx);

            if (rightGetter != null)
                rightGetter.TypeHints.Clear();

            if (!IsLeft && leftType.IsCallableType() && rightType.IsCallableType())
            {
                if (!ctx.CanCombineDelegates(leftType, rightType))
                    Error(Translations.CompilerMessages.DelegatesNotCombinable, leftType, rightType);

                var argTypes = ctx.WrapDelegate(leftType).ArgumentTypes;
                var argGetters = argTypes.Select((a, id) => Expr.GetArg(id)).Cast<NodeBase>().ToArray();

                if (LeftOperand is GetMemberNode)
                    (LeftOperand as GetMemberNode).TypeHints.Clear();

                _Method = ctx.CurrentScope.CreateClosureMethod(ctx, argTypes, ctx.WrapDelegate(rightType).ReturnType);
                _Method.Body =
                    Expr.Block(
                        Expr.Invoke(
                            RightOperand,
                            Expr.Invoke(
                                LeftOperand,
                                argGetters
                            )
                        )
                    );

                var methodBackup = ctx.CurrentMethod;
                ctx.CurrentMethod = _Method;

                var scope = _Method.Scope;
                scope.InitializeScope(ctx);

                _Method.Body.ProcessClosures(ctx);
                _Method.PrepareSelf();

                scope.FinalizeScope(ctx);

                ctx.CurrentMethod = methodBackup;
            }
        }
Ejemplo n.º 19
0
        /// <summary>
        /// Creates a method without setting argument type info.
        /// </summary>
        private MethodEntity createMethodCore(string name, bool isStatic, bool isVirtual, bool prepare)
        {
            var me = new MethodEntity
            {
                Name = name,
                IsStatic = isStatic,
                IsVirtual = isVirtual,
                ContainerType = this,
            };

            _MethodList.Add(me);

            if(prepare)
                me.PrepareSelf();

            return me;
        }
Ejemplo n.º 20
0
        /// <summary>
        /// Creates a wrapper from a method entity.
        /// </summary>
        private MethodWrapper wrapMethod(MethodEntity method, bool isPartial = false)
        {
            return new MethodWrapper
            {
                Name = method.Name,
                Type = method.ContainerType.TypeInfo,

                IsStatic = method.IsStatic,
                IsVirtual = method.IsVirtual,
                IsPartiallyApplied = isPartial,
                IsVariadic = method.IsVariadic,

                MethodInfo = method.MethodInfo,
                ArgumentTypes = method.GetArgumentTypes(this),
                ReturnType = method.ReturnType
            };
        }
Ejemplo n.º 21
0
        /// <summary>
        /// Creates a pure wrapper for parameterless function.
        /// </summary>
        private void createPureWrapper0(MethodEntity wrapper, string pureName)
        {
            var fieldName = string.Format(EntityNames.PureMethodCacheNameTemplate, wrapper.Name);
            var flagName = string.Format(EntityNames.PureMethodCacheFlagNameTemplate, wrapper.Name);

            CreateField(fieldName, wrapper.ReturnTypeSignature, true);
            CreateField(flagName, typeof(bool), true);

            wrapper.Body =  Expr.Block(
                ScopeKind.FunctionRoot,

                // if (not $flag) $cache = $internal (); $flag = true
                Expr.If(
                    Expr.Not(Expr.GetMember(EntityNames.MainTypeName, flagName)),
                    Expr.Block(
                        Expr.SetMember(
                            EntityNames.MainTypeName,
                            fieldName,
                            Expr.Invoke(EntityNames.MainTypeName, pureName)
                        ),
                        Expr.SetMember(EntityNames.MainTypeName, flagName, Expr.True())
                    )
                ),

                // $cache
                Expr.GetMember(EntityNames.MainTypeName, fieldName)
            );
        }