private static BindToValue ( |
||
expr | ||
return |
public static Expression NewPhpArray(Expression[] values) { Expression arr; if (values.Length == 0) { // PhpArray.NewEmpty() return(Expression.Call(typeof(PhpArray), "NewEmpty", Cache.Types.Empty)); // CONSIDER: just PhpArray.Empty } else if (values.Any(IsArgumentUnpacking)) { // TODO: values.Length == 1 && values[0] is PhpArray => return values[0], AddRestriction // unpacking arr = UnpackArgumentsToArray(null, values); } else { // 1:1 arr = Expression.NewArrayInit(typeof(PhpValue), values.Select(x => ConvertExpression.BindToValue(x))); } // PhpArray.New( values[] ) return(Expression.Call(typeof(PhpArray), "New", Cache.Types.Empty, arr)); }
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(); }
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(); }
/// <summary> /// In case the method has [return: CastToFalse], /// the return value -1 or null is converted to false. /// </summary> static Expression BindCastToFalse(Expression expr, bool hasCastToFalse) { if (hasCastToFalse) { var x = Expression.Variable(expr.Type); var assign = Expression.Assign(x, expr); // x = <expr> Expression test; if (expr.Type == typeof(int) || expr.Type == typeof(long)) { // Template: test = x >= 0 test = Expression.GreaterThanOrEqual(assign, Expression.Constant(0)); } else if (expr.Type == typeof(double)) { // Template: test = x >= 0.0 test = Expression.GreaterThanOrEqual(assign, Expression.Constant(0.0)); } else if (expr.Type == typeof(PhpString)) { // Template: test = !x.IsDefault test = Expression.Not(Expression.Property(assign, Cache.PhpString.IsDefault)); } else if (expr.Type.GetTypeInfo().IsValueType == false) // reference type { // Template: test = x != null test = Expression.ReferenceNotEqual(assign, Expression.Constant(null, assign.Type)); } else { Debug.Fail($"[CastToFalse] for an unexpected type {expr.Type.ToString()}."); return(expr); } // Template: test ? (PhpValue)x : PhpValue.False expr = Expression.Condition( test, ConvertExpression.BindToValue(x), Expression.Property(null, Cache.Properties.PhpValue_False)); // return(Expression.Block( expr.Type, new[] { x }, new[] { expr })); } return(expr); }
/// <summary> /// In case the method has [return: CastToFalse], /// the return value -1 or null is converted to false. /// </summary> static Expression BindCastToFalse(Expression expr, bool hasCastToFalse) { if (hasCastToFalse) { var x = Expression.Variable(expr.Type); var assign = Expression.Assign(x, expr); // x = <expr> Expression test; if (expr.Type == typeof(int) || expr.Type == typeof(long)) { // Template: test = x >= 0 test = Expression.GreaterThanOrEqual(assign, Expression.Constant(0)); } else if (expr.Type == typeof(double)) { // Template: test = x >= 0.0 test = Expression.GreaterThanOrEqual(assign, Expression.Constant(0.0)); } else if (expr.Type == typeof(PhpString)) { // Template: test = !x.IsDefault test = Expression.Not(Expression.Property(assign, Cache.PhpString.IsDefault)); } else if (expr.Type.GetTypeInfo().IsValueType == false) // reference type { // Template: test = x != null test = Expression.ReferenceNotEqual(assign, Expression.Constant(null, assign.Type)); } else { Debug.Fail($"[CastToFalse] for an unexpected type {expr.Type.ToString()}."); return(expr); } // Template: test ? (PhpValue)x : PhpValue.False expr = Expression.Condition( test, ConvertExpression.BindToValue(x), Expression.Property(null, Cache.Properties.PhpValue_False)); // return(Expression.Block( expr.Type, new[] { x }, new[] { expr })); } //else if (expr.Type.IsNullable_T(out var t)) // Nullable -> Value | False //{ // // Template: // // tmp = expr // // tmp.HasValue ? tmp.GetValueOrDefault() : FALSE // var tmp = Expression.Variable(expr.Type); // var assign = Expression.Assign(tmp, expr); // tmp = <expr> // var test = Expression.Property(assign, "HasValue"); // expr = Expression.Condition( // test, // ifTrue: ConvertExpression.BindToValue(Expression.Call(tmp, expr.Type.GetMethod("GetValueOrDefault", Array.Empty<Type>()))), // ifFalse: Expression.Property(null, Cache.Properties.PhpValue_False)); // // // return Expression.Block( // expr.Type, // new[] { tmp }, // new[] { expr }); //} return(expr); }
public static Expression UnpackArgumentsToArray(MethodBase[] methods, Expression[] arguments) { //if (arguments.Length == 1 && IsArgumentUnpacking(arguments[0])) //{ // // Template: (...$arg0) // // TODO: if (arg0 is PhpArray) return arg0.ToArray(); //} // create byrefs mask: (but mask of parameters passed by ref) ulong byrefs = 0uL; if (methods != null) { foreach (var m in methods) { var ps = m.GetParameters(); var skip = ps.TakeWhile(IsImplicitParameter).Count(); for (int i = skip; i < ps.Length; i++) { if (ps[i].ParameterType == typeof(PhpAlias)) { byrefs |= (1uL << (i - skip)); } } } } // List<PhpValue> list; var list_var = Expression.Variable(typeof(List <PhpValue>), "list"); var exprs = new List <Expression>(); var byrefs_expr = Expression.Constant(byrefs); // list = new List<PhpValue>( LENGTH ) exprs.Add(Expression.Assign(list_var, Expression.New(list_var.Type.GetConstructor(Cache.Types.Int), Expression.Constant(arguments.Length)))); // arguments.foreach( Unpack(list, arg_i) ); foreach (var arg in arguments) { if (IsArgumentUnpacking(arg)) { Expression unpackexpr; // Template: Operators.Unpack(list, arg, byrefs) // Unpack(List<PhpValue> stack, PhpValue|PhpArray|Traversable argument, ulong byrefs) var arg_value = Expression.Field(arg, "Value"); // UnpackingParam<>.Value //if (typeof(PhpArray).IsAssignableFrom(arg_value.Type)) // TODO //{ //} //else if (typeof(Traversable).IsAssignableFrom(arg_value.Type)) // TODO //{ //} //else // PhpValue { unpackexpr = Expression.Call( typeof(Operators), "Unpack", Cache.Types.Empty, list_var, ConvertExpression.BindToValue(arg_value), byrefs_expr); } exprs.Add(unpackexpr); } else { // list.Add((PhpValue)arg) exprs.Add(Expression.Call(list_var, "Add", Cache.Types.Empty, ConvertExpression.BindToValue(arg))); } } // return list.ToArray() exprs.Add(Expression.Call(list_var, "ToArray", Cache.Types.Empty)); // return(Expression.Block(new[] { list_var }, exprs)); }