Esempio n. 1
0
        static Expression BindAccess(Expression expr, Expression ctx, AccessMask access, Expression rvalue)
        {
            if (access.EnsureObject())
            {
                if (expr.Type == typeof(PhpAlias))
                {
                    // ((PhpAlias)fld).EnsureObject()
                    expr = Expression.Call(expr, Cache.Operators.PhpAlias_EnsureObject);
                }
                else if (expr.Type == typeof(PhpValue))
                {
                    // ((PhpValue)fld).EnsureObject()
                    expr = Expression.Call(expr, Cache.Operators.PhpValue_EnsureObject);
                }
                else
                {
                    // getter // TODO: ensure it is not null
                    Debug.Assert(!expr.Type.GetTypeInfo().IsValueType);
                }
            }
            else if (access.EnsureArray())
            {
                if (expr.Type == typeof(PhpAlias))
                {
                    // ((PhpAlias)fld).EnsureArray()
                    expr = Expression.Call(expr, Cache.Operators.PhpAlias_EnsureArray);
                }
                else if (expr.Type == typeof(PhpValue))
                {
                    // ((PhpValue)fld).EnsureArray()
                    expr = Expression.Call(expr, Cache.Operators.PhpValue_EnsureArray);
                }
                else if (expr.Type == typeof(PhpArray))
                {
                    // (PhpArray)fld // TODO: ensure it is not null
                }
                else
                {
                    // Operators.EnsureArray( fld )
                    // TODO: string
                    expr = Expression.Call(Cache.Operators.Object_EnsureArray, expr);
                }
            }
            else if (access.EnsureAlias())
            {
                if (expr.Type == typeof(PhpAlias))
                {
                    // (PhpAlias)getter
                }
                else if (expr.Type == typeof(PhpValue))
                {
                    // ((PhpValue)fld).EnsureAlias()
                    expr = Expression.Call(expr, Cache.Operators.PhpValue_EnsureAlias);
                }
                else
                {
                    // getter // cannot read as reference
                }
            }
            else if (access.WriteAlias())
            {
                // write alias

                Debug.Assert(rvalue.Type == typeof(PhpAlias));
                rvalue = ConvertExpression.Bind(rvalue, typeof(PhpAlias), ctx);

                if (expr.Type == typeof(PhpAlias))
                {
                    // ok
                }
                else if (expr.Type == typeof(PhpValue))
                {
                    // fld = PhpValue.Create(alias)
                    rvalue = Expression.Call(typeof(PhpValue).GetMethod("Create", Cache.Types.PhpAlias), rvalue);
                }
                else
                {
                    // fld is not aliasable
                    Debug.Assert(false, "Cannot assign aliased value to field of type " + expr.Type.ToString());
                    rvalue = ConvertExpression.Bind(rvalue, expr.Type, ctx);
                }

                expr = Expression.Assign(expr, rvalue);
            }
            else if (access.Unset())
            {
                Debug.Assert(rvalue == null);

                expr = Expression.Assign(expr, ConvertExpression.BindDefault(expr.Type));
            }
            else if (access.Write())
            {
                // write by value

                if (expr.Type == typeof(PhpAlias))
                {
                    // Template: fld.Value = (PhpValue)value
                    expr = Expression.Assign(Expression.Field(expr, Cache.PhpAlias.Value), ConvertExpression.Bind(rvalue, typeof(PhpValue), ctx));
                }
                else if (expr.Type == typeof(PhpValue))
                {
                    // Template: Operators.SetValue(ref fld, (PhpValue)value)
                    expr = Expression.Call(Cache.Operators.SetValue_PhpValueRef_PhpValue, expr, ConvertExpression.Bind(rvalue, typeof(PhpValue), ctx));
                }
                else
                {
                    // Template: fld = value
                    // default behaviour by value to value
                    expr = Expression.Assign(expr, ConvertExpression.Bind(rvalue, expr.Type, ctx));
                }
            }
            else if (access.ReadValue())
            {
                // dereference
                if (expr.Type == typeof(PhpValue))
                {
                    // Template: value.GetValue().DeepCopy()
                    expr = Expression.Call(expr, Cache.Operators.PhpValue_GetValue);
                }
                else if (expr.Type == typeof(PhpAlias))
                {
                    // Template: alias.Value // expecting alias cannot be null ref
                    expr = Expression.Field(expr, Cache.PhpAlias.Value);
                }
            }
            else if (access.ReadValueCopy())
            {
                // dereference & copy
                if (expr.Type == typeof(PhpValue))
                {
                    // Template: value.GetValue().DeepCopy()
                    expr = Expression.Call(Expression.Call(expr, Cache.Operators.PhpValue_GetValue), Cache.Operators.PhpValue_DeepCopy);
                }
                else if (expr.Type == typeof(PhpAlias))
                {
                    // TODO: specify - ReadCopy | ReadValue | ReadValueCopy - currently not consistent
                }
            }
            else if (access.Isset())
            {
                if (expr.Type == typeof(PhpAlias))
                {
                    expr = Expression.Field(expr, Cache.PhpAlias.Value);
                }

                //
                if (expr.Type == typeof(PhpValue))
                {
                    // Template: Operators.IsSet( value )
                    expr = Expression.Call(Cache.Operators.IsSet_PhpValue, expr);
                }
                else if (!expr.Type.GetTypeInfo().IsValueType)
                {
                    // Template: value != null
                    expr = Expression.ReferenceNotEqual(expr, Expression.Constant(null, typeof(object)));
                }
                else
                {
                    // if there is bound typed symbol, it is always set:
                    expr = Expression.Constant(true, typeof(bool));
                }
            }

            // Read, IsSet
            return(expr);
        }