Skip to content

Commit

Permalink
+= operator for event+= callable
Browse files Browse the repository at this point in the history
ref #1141
  • Loading branch information
jakubmisek committed May 6, 2024
1 parent 9df0cb0 commit 6761242
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 10 deletions.
49 changes: 40 additions & 9 deletions src/Peachpie.Runtime/ClrEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@

namespace Pchp.Core
{
public class ClrEvent<TDelegate> : IPhpCallable where TDelegate : Delegate
internal interface IClrEvent
{
IDisposable Add(IPhpCallable callable);
}

public class ClrEvent<TDelegate> : IPhpConvertible, IClrEvent, IPhpCallable where TDelegate : Delegate
{
sealed class Hook : IDisposable
{
Expand Down Expand Up @@ -39,6 +44,9 @@ public void Dispose()
}
}

[PhpHidden]
protected readonly Context _ctx;

[PhpHidden]
public EventInfo EventInfo { get; }

Expand All @@ -57,6 +65,8 @@ public void Dispose()

internal ClrEvent(Context ctx, object target, EventInfo eventInfo)
{
_ctx = ctx;

this.Target = target;
this.EventInfo = eventInfo ?? throw new ArgumentNullException(nameof(eventInfo));
}
Expand All @@ -79,6 +89,15 @@ public void remove(TDelegate callback)
throw new NotSupportedException();
}

#region IClrEvent

IDisposable/*!*/IClrEvent.Add(IPhpCallable callable) =>
this.add(
callback: PhpCallableToDelegate<TDelegate>.Get(callable, _ctx)
);

#endregion

#region IPhpCallable

PhpValue IPhpCallable.Invoke(Context ctx, params PhpValue[] arguments)
Expand All @@ -89,15 +108,27 @@ PhpValue IPhpCallable.Invoke(Context ctx, params PhpValue[] arguments)

PhpValue IPhpCallable.ToPhpValue() => PhpValue.FromClr(this);

//public PhpValue __invoke([ImportValue(ImportValueAttribute.ValueSpec.CallerClass)] RuntimeTypeHandle caller, params PhpValue[] arguments)
//{
// if (caller.Equals(default(RuntimeTypeHandle)))
// {
// return false;
// }
#endregion

#region IPhpConvertible

double IPhpConvertible.ToDouble() => throw new NotSupportedException();

long IPhpConvertible.ToLong() => throw new NotSupportedException();

bool IPhpConvertible.ToBoolean() => throw new NotSupportedException();

Convert.NumberInfo IPhpConvertible.ToNumber(out PhpNumber number)
{
number = 0;
return Convert.NumberInfo.Unconvertible;
}

string IPhpConvertible.ToString() => name;

object IPhpConvertible.ToClass() => this;

// return PhpValue.Null;
//}
PhpArray IPhpConvertible.ToArray() => throw new NotSupportedException();

#endregion
}
Expand Down
10 changes: 9 additions & 1 deletion src/Peachpie.Runtime/Dynamic/BinderHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,14 @@ public static Expression BindAccess(Expression expr, Expression ctx, AccessMask
// Template: Operators.SetValue(ref fld, (PhpValue)value)
expr = Expression.Call(Cache.Operators.SetValue_PhpValueRef_PhpValue, expr, ConvertExpression.Bind(rvalue, typeof(PhpValue), ctx));
}
else if (expr.Type.GetGenericTypeDefinition() == typeof(ClrEvent<>))
{
// Template: $object->eventHandler += rvalue; return rvalue;
// rvalue is (eventHadler + callable)
expr = Expression.Block(
rvalue
);
}
else
{
// Template: fld = value
Expand Down Expand Up @@ -859,7 +867,7 @@ public static Expression BindField(PhpTypeInfo type, Type classCtx, Expression t
// lookup a declared field
if (TryResolveDeclaredProperty(type, classCtx, target == null, field, out var prop))
{
if (access.Write() && prop.IsReadOnly)
if (access.Write() && prop.IsReadOnly && !(prop is PhpPropertyInfo.ClrEvent))
{
return BindInvalidPropertyAccess(type.Name, field, classCtx, prop);
}
Expand Down
1 change: 1 addition & 0 deletions src/Peachpie.Runtime/PhpCallback.cs
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,7 @@ public static TFunc Get(IPhpCallable callable, Context ctx)
if (typeof(TFunc) == typeof(Action)) return (TFunc)(object)new Action(() => callable.Invoke(ctx));
if (typeof(TFunc) == typeof(Func<bool>)) return (TFunc)(object)new Func<bool>(() => (bool)callable.Invoke(ctx));
if (typeof(TFunc) == typeof(Func<long, long>)) return (TFunc)(object)new Func<long, long>((p1) => (long)callable.Invoke(ctx, p1));
if (typeof(TFunc) == typeof(EventHandler)) return (TFunc)(object)new EventHandler((s, a) => callable.Invoke(ctx, PhpValue.FromClass(s), PhpValue.FromClass(a)));

//
return Dynamic.BinderHelpers.CreateDelegate<TFunc>(callable, ctx);
Expand Down
6 changes: 6 additions & 0 deletions src/Peachpie.Runtime/PhpNumber.cs
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,12 @@ static PhpValue AddNonNumbers(ref PhpValue x, ref PhpValue y)
{
return (PhpValue)PhpArray.Union(arr_x, arr_y);
}
else if (x.AsObject() is IClrEvent clrEvent)
{
// event += function
clrEvent.Add(y.AsCallable());
return x; // returns itself
}

//PhpException.UnsupportedOperandTypes();
//return 0;
Expand Down

0 comments on commit 6761242

Please sign in to comment.