public static BindDefault ( |
||
t | ||
Résultat |
public override Expression BindArgument(int srcarg, ParameterInfo targetparam = null) { Debug.Assert(srcarg >= 0); if (TryBindArgument(srcarg, targetparam?.ParameterType, out var expr)) { return(expr); } else { if (targetparam != null) { if (targetparam.HasDefaultValue) { return(ConvertExpression.Bind(Expression.Constant(targetparam.DefaultValue), targetparam.ParameterType, _ctx)); } else { var defaultValueAttr = targetparam.GetCustomAttribute <DefaultValueAttribute>(); if (defaultValueAttr != null) { return(ConvertExpression.Bind(BindDefaultValue(targetparam.Member.DeclaringType, defaultValueAttr), targetparam.ParameterType, _ctx)); } } // return(ConvertExpression.BindDefault(targetparam.ParameterType)); } return(Expression.Constant(null, typeof(object))); } }
public override DynamicMetaObject Bind(DynamicMetaObject target, DynamicMetaObject[] args) { var restrictions = BindingRestrictions.Empty; PhpTypeInfo phptype; Expression target_expr; // var ctx = args[0]; var fldName = ResolveName(args, ref restrictions); // if (target.LimitType == typeof(PhpTypeInfo)) // static field { target_expr = null; phptype = (PhpTypeInfo)target.Value; // restrictions = restrictions.Merge(BindingRestrictions.GetInstanceRestriction(target.Expression, phptype)); } else { var isobject = BinderHelpers.TryTargetAsObject(target, out DynamicMetaObject instance); restrictions = restrictions.Merge(instance.Restrictions); if (isobject == false) { var defaultexpr = ConvertExpression.BindDefault(_returnType); if (!_access.Quiet()) { // PhpException.VariableMisusedAsObject(target, _access.ReadRef) var throwcall = Expression.Call(typeof(PhpException), "VariableMisusedAsObject", Array.Empty <Type>(), ConvertExpression.BindToValue(target.Expression), Expression.Constant(_access.EnsureAlias())); defaultexpr = Expression.Block(throwcall, defaultexpr); } return(new DynamicMetaObject(defaultexpr, restrictions)); } phptype = instance.RuntimeType.GetPhpTypeInfo(); target_expr = target_expr = Expression.Convert(instance.Expression, instance.RuntimeType); } Debug.Assert(IsClassConst == (target_expr == null)); // var getter = IsClassConst ? BinderHelpers.BindClassConstant(phptype, _classContext, fldName, ctx.Expression) : BinderHelpers.BindField(phptype, _classContext, target_expr, fldName, ctx.Expression, _access, null); if (getter != null) { // return(new DynamicMetaObject(ConvertExpression.Bind(getter, _returnType, ctx.Expression), restrictions)); } // field not found throw new NotImplementedException(); }
protected override Expression BindMissingMethod(CallSiteContext bound) { if (bound.TargetType == null) // already reported - class cannot be found { return(ConvertExpression.BindDefault(this.ReturnType)); } var call = BinderHelpers.FindMagicMethod(bound.TargetType, (bound.TargetInstance == null) ? TypeMethods.MagicMethods.__callstatic : TypeMethods.MagicMethods.__call); if (call != null) { var name_expr = (_name != null) ? Expression.Constant(_name) : bound.IndirectName; // T.__callStatic(name, array) var call_args = new Expression[] { name_expr, BinderHelpers.NewPhpArray(bound.Arguments), }; return(OverloadBinder.BindOverloadCall(_returnType, bound.TargetInstance, call.Methods, bound.Context, call_args, true, lateStaticType: bound.TargetType)); } // return(base.BindMissingMethod(bound)); }
protected override Expression BindMissingMethod(CallSiteContext bound) { var name_expr = (_name != null) ? Expression.Constant(_name) : bound.IndirectName; // resolve target expression: var isobject = bound.TargetType != null; if (isobject == false) { /* Template: * PhpException.MethodOnNonObject(name_expr); // aka PhpException.Throw(Error, method_called_on_non_object, name_expr) * return NULL; */ var throwcall = Expression.Call(typeof(PhpException), "MethodOnNonObject", Array.Empty <Type>(), ConvertExpression.Bind(name_expr, typeof(string), bound.Context)); return(Expression.Block(throwcall, ConvertExpression.BindDefault(this.ReturnType))); } var call = BinderHelpers.FindMagicMethod(bound.TargetType, TypeMethods.MagicMethods.__call); if (call != null) { // target.__call(name, array) var call_args = new Expression[] { name_expr, BinderHelpers.NewPhpArray(bound.Arguments), }; return(OverloadBinder.BindOverloadCall(_returnType, bound.TargetInstance, call.Methods, bound.Context, call_args, false)); } return(base.BindMissingMethod(bound)); }
public override Expression BindArgument(int srcarg, ParameterInfo targetparam = null) { Debug.Assert(srcarg >= 0); if (srcarg < _args.Length) { var expr = _args[srcarg]; return((targetparam != null) ? ConvertExpression.Bind(expr, targetparam.ParameterType, _ctx) : expr); } else { if (targetparam != null) { if (targetparam.HasDefaultValue) { return(ConvertExpression.Bind(Expression.Constant(targetparam.DefaultValue), targetparam.ParameterType, _ctx)); } else if (targetparam.GetCustomAttribute <DefaultValueAttribute>() != null) { // TODO: DefaultValueAttribute //Debug.Fail("default value lost"); } return(ConvertExpression.BindDefault(targetparam.ParameterType)); } return(Expression.Constant(null, typeof(object))); } }
public override Expression BindArgument(int srcarg, ParameterInfo targetparam = null) { Debug.Assert(srcarg >= 0); if (srcarg < _args.Length) { var expr = _args[srcarg]; return((targetparam != null) ? ConvertExpression.Bind(expr, targetparam.ParameterType, _ctx) : expr); } else { if (targetparam != null) { if (targetparam.HasDefaultValue) { return(ConvertExpression.Bind(Expression.Constant(targetparam.DefaultValue), targetparam.ParameterType, _ctx)); } return(ConvertExpression.BindDefault(targetparam.ParameterType)); } return(Expression.Constant(null, typeof(object))); } }
public override Expression BindArgument(int srcarg, ParameterInfo targetparam = null) { Debug.Assert(srcarg >= 0); // cache the argument value var key = new TmpVarKey() { Priority = 0 /*first*/, ArgIndex = srcarg, Prefix = "arg" }; TmpVarValue value; if (!_tmpvars.TryGetValue(key, out value)) { value = new TmpVarValue(); value.TrueInitializer = Expression.ArrayIndex(_argsarray, Expression.Constant(srcarg)); value.FalseInitializer = ConvertExpression.BindDefault(value.TrueInitializer.Type); // ~ default(_argsarray.Type.GetElementType()) value.Expression = Expression.Variable(value.TrueInitializer.Type, "arg_" + srcarg); // _tmpvars[key] = value; } if (targetparam != null) { // create specialized variable with default value if (targetparam.HasDefaultValue) { var @default = targetparam.DefaultValue; var defaultValueExpr = Expression.Constant(@default); var defaultValueStr = (@default != null) ? @default.ToString() : "NULL"; // var key2 = new TmpVarKey() { Priority = 1 /*after key*/, ArgIndex = srcarg, Prefix = "arg(" + defaultValueStr + ")" }; TmpVarValue value2; if (!_tmpvars.TryGetValue(key2, out value2)) { value2 = new TmpVarValue(); value2.TrueInitializer = ConvertExpression.Bind(value.Expression, targetparam.ParameterType, _ctx); // reuse the value already obtained from argv value2.FalseInitializer = ConvertExpression.Bind(defaultValueExpr, value2.TrueInitializer.Type, _ctx); // ~ default(targetparam) value2.Expression = Expression.Variable(value2.TrueInitializer.Type, "arg_" + srcarg + "_" + defaultValueStr); // _tmpvars[key2] = value2; } return(value2.Expression); // already converted to targetparam.ParameterType } } return((targetparam == null) ? value.Expression : ConvertExpression.Bind(value.Expression, targetparam.ParameterType, _ctx)); }
protected virtual Expression BindMissingMethod(CallSiteContext bound) { /* Template: * PhpException.UndefinedFunctionCalled(name); // aka PhpException.Throw(Error, undefined_function_called, name) * return NULL; */ var throwcall = Expression.Call(typeof(PhpException), "UndefinedFunctionCalled", Array.Empty <Type>(), bound.IndirectName ?? Expression.Constant(bound.Name)); return(Expression.Block(throwcall, ConvertExpression.BindDefault(this.ReturnType))); }
public override DynamicMetaObject Bind(DynamicMetaObject target, DynamicMetaObject[] args) { bool hasTargetInstance = (target.LimitType != typeof(TargetTypeParam)); var bound = new CallSiteContext(!hasTargetInstance) { ClassContext = _classContext, Name = _name } .ProcessArgs(target, args, hasTargetInstance); if (hasTargetInstance) { var isobject = bound.TargetType != null; if (isobject == false) { var defaultexpr = ConvertExpression.BindDefault(_returnType); if (!_access.Quiet()) { // PhpException.VariableMisusedAsObject(target, _access.ReadRef) var throwcall = BinderHelpers.VariableMisusedAsObject(target.Expression, _access.EnsureAlias()); defaultexpr = Expression.Block(throwcall, defaultexpr); } return(new DynamicMetaObject(defaultexpr, bound.Restrictions)); } // instance := (T)instance bound.TargetInstance = Expression.Convert(bound.TargetInstance, bound.TargetType.Type); } Debug.Assert(IsClassConst ? (bound.TargetInstance == null) : true); // var getter = IsClassConst ? BinderHelpers.BindClassConstant(bound.TargetType, bound.ClassContext, bound.Name, bound.Context) : BinderHelpers.BindField(bound.TargetType, bound.ClassContext, bound.TargetInstance, bound.Name, bound.Context, _access, null); if (getter != null) { // return(new DynamicMetaObject(ConvertExpression.Bind(getter, _returnType, bound.Context), bound.Restrictions)); } if (IsClassConst) { // error: constant not defined // ... } // unreachable: property not found throw new InvalidOperationException($"{bound.TargetType.Name}::{bound.Name} could not be resolved."); }
protected virtual Expression BindMissingMethod(CallSiteContext bound) { /* Template: * PhpException.UndefinedFunctionCalled(name); * return NULL; */ var throwcall = bound.TargetType != null ? Expression.Call(typeof(PhpException), "UndefinedMethodCalled", Array.Empty <Type>(), Expression.Constant(bound.TargetType.Name), bound.IndirectName ?? Expression.Constant(bound.Name)) : Expression.Call(typeof(PhpException), "UndefinedFunctionCalled", Array.Empty <Type>(), bound.IndirectName ?? Expression.Constant(bound.Name)); return(Expression.Block(throwcall, ConvertExpression.BindDefault(this.ReturnType))); }
public override DynamicMetaObject Bind(DynamicMetaObject target, DynamicMetaObject[] args) { bool hasTargetInstance = (target.LimitType != typeof(TargetTypeParam)); var bound = new CallSiteContext() { ClassContext = _classContext, Name = _name } .ProcessArgs(target, args, hasTargetInstance); if (hasTargetInstance) { var isobject = bound.TargetType != null; if (isobject == false) { var defaultexpr = ConvertExpression.BindDefault(_returnType); if (!_access.Quiet()) { // PhpException.VariableMisusedAsObject(target, _access.ReadRef) var throwcall = Expression.Call(typeof(PhpException), "VariableMisusedAsObject", Array.Empty <Type>(), ConvertExpression.BindToValue(target.Expression), Expression.Constant(_access.EnsureAlias())); defaultexpr = Expression.Block(throwcall, defaultexpr); } return(new DynamicMetaObject(defaultexpr, bound.Restrictions)); } // instance := (T)instance bound.TargetInstance = Expression.Convert(bound.TargetInstance, bound.TargetType.Type.AsType()); } Debug.Assert(IsClassConst ? (bound.TargetInstance == null) : true); // var getter = IsClassConst ? BinderHelpers.BindClassConstant(bound.TargetType, bound.ClassContext, bound.Name, bound.Context) : BinderHelpers.BindField(bound.TargetType, bound.ClassContext, bound.TargetInstance, bound.Name, bound.Context, _access, null); if (getter != null) { // return(new DynamicMetaObject(ConvertExpression.Bind(getter, _returnType, bound.Context), bound.Restrictions)); } // field not found throw new NotImplementedException(); }
protected override Expression BindMissingMethod(CallSiteContext bound) { var type = bound.TargetType; if (type == null) // already reported - class cannot be found { return(ConvertExpression.BindDefault(this.ReturnType)); } if (bound.TargetInstance != null && bound.CurrentTargetInstance != null) // it has been checked it is a subclass of TargetType { // ensure current scope's __call() is favoured over the specified class type = bound.CurrentTargetInstance.GetPhpTypeInfo(); } var call = BinderHelpers.FindMagicMethod(type, (bound.TargetInstance == null) ? TypeMethods.MagicMethods.__callstatic : TypeMethods.MagicMethods.__call); if (call != null) { Expression[] call_args; var name_expr = (_name != null) ? Expression.Constant(_name) : bound.IndirectName; if (call.Methods.All(IsClrMagicCallWithParams)) { // Template: target.__call(name, arg1, arg2, ...) // flatterns the arguments: call_args = ArrayUtils.AppendRange(name_expr, bound.Arguments); } else { // Template: target.__call(name, array) // regular PHP behavior: call_args = new Expression[] { name_expr, BinderHelpers.NewPhpArray(bound.Arguments, bound.Context, bound.ClassContext), }; } return(OverloadBinder.BindOverloadCall(_returnType, bound.TargetInstance, call.Methods, bound.Context, call_args, isStaticCallSyntax: true, lateStaticType: bound.TargetType, classContext: bound.ClassContext)); } // return(base.BindMissingMethod(bound)); }
protected override Expression BindMissingMethod(CallSiteContext bound) { var name_expr = (_name != null) ? Expression.Constant(_name) : bound.IndirectName; // resolve target expression: var isobject = bound.TargetType != null; if (isobject == false) { /* Template: * PhpException.MethodOnNonObject(name_expr); * return NULL; */ var throwcall = Expression.Call(typeof(PhpException), "MethodOnNonObject", Array.Empty <Type>(), ConvertExpression.Bind(name_expr, typeof(string), bound.Context)); return(Expression.Block(throwcall, ConvertExpression.BindDefault(this.ReturnType))); } var call = BinderHelpers.FindMagicMethod(bound.TargetType, TypeMethods.MagicMethods.__call); if (call != null) { Expression[] call_args; if (call.Methods.All(IsClrMagicCallWithParams)) { // Template: target.__call(name, arg1, arg2, ...) // flatterns the arguments: call_args = ArrayUtils.AppendRange(name_expr, bound.Arguments); } else { // Template: target.__call(name, array) // regular PHP behavior: call_args = new Expression[] { name_expr, BinderHelpers.NewPhpArray(bound.Arguments, bound.Context, bound.ClassContext), }; } return(OverloadBinder.BindOverloadCall(_returnType, bound.TargetInstance, call.Methods, bound.Context, call_args, false)); } return(base.BindMissingMethod(bound)); }
protected override Expression BindMissingMethod(DynamicMetaObject ctx, PhpTypeInfo tinfo, DynamicMetaObject nameMeta, DynamicMetaObject target, IList <DynamicMetaObject> args, ref BindingRestrictions restrictions) { var name_expr = (_name != null) ? Expression.Constant(_name) : nameMeta?.Expression; // resolve target expression: Expression target_expr; object target_value; BinderHelpers.TargetAsObject(target, out target_expr, out target_value, ref restrictions); if (target_value == null) { /* Template: * PhpException.MethodOnNonObject(name_expr); // aka PhpException.Throw(Error, method_called_on_non_object, name_expr) * return NULL; */ var throwcall = Expression.Call(typeof(PhpException), "MethodOnNonObject", Array.Empty <Type>(), ConvertExpression.Bind(name_expr, typeof(string), ctx.Expression)); return(Expression.Block(throwcall, ConvertExpression.BindDefault(this.ReturnType))); } Debug.Assert(ReflectionUtils.IsClassType(target_value.GetType().GetTypeInfo())); tinfo = target_value.GetPhpTypeInfo(); var call = BinderHelpers.FindMagicMethod(tinfo, TypeMethods.MagicMethods.__call); if (call != null) { // target.__call(name, array) var call_args = new Expression[] { name_expr, BinderHelpers.NewPhpArray(ctx.Expression, args.Select(a => a.Expression)), }; return(OverloadBinder.BindOverloadCall(_returnType, target.Expression, call.Methods, ctx.Expression, call_args)); } return(base.BindMissingMethod(ctx, tinfo, nameMeta, target, args, ref restrictions)); }
public override Expression BindArgument(int srcarg, ParameterInfo targetparam = null) { Debug.Assert(srcarg >= 0); // cache the argument value var key = new TmpVarKey() { Priority = 0 /*first*/, ArgIndex = srcarg, Prefix = "arg" }; TmpVarValue value; if (!_tmpvars.TryGetValue(key, out value)) { value = new TmpVarValue(); value.TrueInitializer = Expression.ArrayIndex(_argsarray, Expression.Constant(srcarg)); value.FalseInitializer = ConvertExpression.BindDefault(value.TrueInitializer.Type); // ~ default(_argsarray.Type.GetElementType()) value.Expression = Expression.Variable(value.TrueInitializer.Type, "arg_" + srcarg); // _tmpvars[key] = value; } if (targetparam != null) { DefaultValueAttribute defaultValueAttr = null; // create specialized variable with default value if (targetparam.HasDefaultValue || (defaultValueAttr = targetparam.GetCustomAttribute <DefaultValueAttribute>()) != null) { Debug.Assert(!targetparam.ParameterType.IsByRef); // parameter with a default value cannot be byref (at least we don't expect it) // just for debugging purposes: var defaultValueStr = defaultValueAttr != null ? defaultValueAttr.FieldName : targetparam.DefaultValue?.ToString() ?? "NULL"; // the default value expression var defaultValueExpr = defaultValueAttr != null ? BindDefaultValue(targetparam.Member.DeclaringType, defaultValueAttr) : Expression.Constant(targetparam.DefaultValue); // var key2 = new TmpVarKey() { Priority = 1 /*after key*/, ArgIndex = srcarg, Prefix = "default(" + defaultValueStr + ")" }; TmpVarValue value2; if (!_tmpvars.TryGetValue(key2, out value2)) { value2 = new TmpVarValue(); value2.TrueInitializer = ConvertExpression.Bind(value.Expression, targetparam.ParameterType, _ctx); // reuse the value already obtained from argv value2.FalseInitializer = ConvertExpression.Bind(defaultValueExpr, value2.TrueInitializer.Type, _ctx); // ~ default(targetparam) value2.Expression = Expression.Variable(value2.TrueInitializer.Type, "default_" + srcarg + "_" + defaultValueStr); // _tmpvars[key2] = value2; } return(value2.Expression); // already converted to targetparam.ParameterType } } if (targetparam == null) { return(value.Expression); } else { var ptype = targetparam.ParameterType; // TODO: ptype.IsByRef -> implement write-back after the invocation if (ptype.IsByRef) { ptype = ptype.GetElementType(); // LINQ will create a local variable for it implicitly } return(ConvertExpression.Bind(value.Expression, ptype, _ctx)); } }
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 { // getter } } 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.PropertyOrField(expr, "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.ReadCopy()) { // 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)) { } } // return(expr); }
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); }