Example #1
0
            public ClrFieldProperty(PhpTypeInfo tinfo, FieldInfo field)
                : base(tinfo)
            {
                Field = field ?? throw new ArgumentNullException(nameof(field));

                //
                _lazyGetter       = new Lazy <Func <Context, object, PhpValue> >(() => (Func <Context, object, PhpValue>)CompileAccess(AccessMask.Read));
                _lazyEnsureAlias  = new Lazy <Func <Context, object, PhpAlias> >(() => (Func <Context, object, PhpAlias>)CompileAccess(AccessMask.ReadRef));
                _lazyEnsureObject = new Lazy <Func <Context, object, object> >(() => (Func <Context, object, object>)CompileAccess(AccessMask.EnsureObject));
                _lazyEnsureArray  = new Lazy <Func <Context, object, IPhpArray> >(() => (Func <Context, object, IPhpArray>)CompileAccess(AccessMask.EnsureArray));

                // SetValue(instance, PhpValue): void
                _lazySetValue = new Lazy <Action <Context, object, PhpValue> >(() =>
                {
                    if (IsReadOnly)
                    {
                        // error
                        return((_, _instance, _value) =>
                        {
                            PhpException.ErrorException(Resources.ErrResources.readonly_property_written, ContainingType.Name, PropertyName);
                        });
                    }

                    var pctx      = Expression.Parameter(typeof(Context));
                    var pinstance = Expression.Parameter(typeof(object));
                    var pvalue    = Expression.Parameter(typeof(PhpValue));

                    // field_expr: <instance>.<field>
                    var field_expr = Bind(pctx, Expression.Convert(pinstance, Field.DeclaringType));

                    // expr: <field> := <value>
                    // var expr = BinderHelpers.BindAccess(field_expr, pctx, AccessMask.Write, pvalue); // <-- does not allow passing PhpAlias

                    Expression assign_expr = Expression.Block(
                        Expression.Assign(field_expr, ConvertExpression.Bind(pvalue, Field.FieldType, pctx)),
                        Expression.Empty());

                    // when assigning to PhpValue, we have to write by value or by ref
                    if (Field.FieldType == typeof(PhpValue))
                    {
                        // assign_expr: value.IsAlias ? (field_expr = value) : SetValue(ref field_expr, value)
                        assign_expr = Expression.Condition(
                            test: Expression.Property(pvalue, Cache.Properties.PhpValue_IsAlias),
                            ifTrue: assign_expr,
                            ifFalse: Expression.Call(Cache.Operators.SetValue_PhpValueRef_PhpValue, field_expr, pvalue)
                            );
                    }

                    //
                    var lambda = Expression.Lambda(assign_expr, pctx, pinstance, pvalue);

                    return((Action <Context, object, PhpValue>)lambda.Compile());
                });
            }
Example #2
0
            public ClrProperty(PhpTypeInfo tinfo, PropertyInfo property)
                : base(tinfo)
            {
                Debug.Assert(property != null);
                _property = property;

                _lazyGetter = new Lazy <Func <object, PhpValue> >(() =>
                {
                    var pinstance = Expression.Parameter(typeof(object));

                    var expr = Bind(null, Expression.Convert(pinstance, _property.DeclaringType));
                    expr     = ConvertExpression.BindToValue(expr);

                    //
                    return((Func <object, PhpValue>)Expression.Lambda(expr, true, pinstance).Compile());
                });

                // SetValue(instance, PhpValue): void
                _lazySetValue = new Lazy <Action <Context, object, PhpValue> >(() =>
                {
                    if (IsReadOnly)
                    {
                        // error
                        return(new Action <Context, object, PhpValue>((_, _instance, _value) =>
                        {
                            PhpException.ErrorException(Resources.ErrResources.readonly_property_written, ContainingType.Name, PropertyName);
                        }));
                    }

                    var pctx      = Expression.Parameter(typeof(Context));
                    var pinstance = Expression.Parameter(typeof(object));
                    var pvalue    = Expression.Parameter(typeof(PhpValue));

                    // expr: <instance>.<field>
                    var expr = Bind(pctx, Expression.Convert(pinstance, _property.DeclaringType));

                    // expr: <property> := <value>
                    expr = Expression.Assign(expr, ConvertExpression.Bind(pvalue, expr.Type, pctx));    // TODO: PHP semantic (Operators.SetValue)

                    // {expr}: void
                    var lambda = Expression.Lambda(Expression.Block(expr, Expression.Empty()), pctx, pinstance, pvalue);

                    return((Action <Context, object, PhpValue>)lambda.Compile());
                });
            }