|
|
|
@ -206,38 +206,64 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions |
|
|
|
Setters.Insert(0, new UnsetValueSetter(types, original.DeclaringType, field)); |
|
|
|
} |
|
|
|
|
|
|
|
abstract class AvaloniaPropertyCustomSetter : IXamlPropertySetter, IXamlEmitablePropertySetter<IXamlILEmitter> |
|
|
|
abstract class AvaloniaPropertyCustomSetter : IXamlILOptimizedEmitablePropertySetter, IEquatable<AvaloniaPropertyCustomSetter> |
|
|
|
{ |
|
|
|
protected AvaloniaXamlIlWellKnownTypes Types; |
|
|
|
protected IXamlField AvaloniaProperty; |
|
|
|
protected readonly AvaloniaXamlIlWellKnownTypes Types; |
|
|
|
protected readonly IXamlField AvaloniaProperty; |
|
|
|
|
|
|
|
public AvaloniaPropertyCustomSetter(AvaloniaXamlIlWellKnownTypes types, |
|
|
|
protected AvaloniaPropertyCustomSetter( |
|
|
|
AvaloniaXamlIlWellKnownTypes types, |
|
|
|
IXamlType declaringType, |
|
|
|
IXamlField avaloniaProperty) |
|
|
|
IXamlField avaloniaProperty, |
|
|
|
bool allowNull) |
|
|
|
{ |
|
|
|
Types = types; |
|
|
|
AvaloniaProperty = avaloniaProperty; |
|
|
|
TargetType = declaringType; |
|
|
|
BinderParameters = new PropertySetterBinderParameters |
|
|
|
{ |
|
|
|
AllowXNull = allowNull, |
|
|
|
AllowRuntimeNull = allowNull |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
public IXamlType TargetType { get; } |
|
|
|
|
|
|
|
public PropertySetterBinderParameters BinderParameters { get; } = new PropertySetterBinderParameters |
|
|
|
{ |
|
|
|
AllowXNull = false |
|
|
|
}; |
|
|
|
public PropertySetterBinderParameters BinderParameters { get; } |
|
|
|
|
|
|
|
public IReadOnlyList<IXamlType> Parameters { get; set; } |
|
|
|
public abstract void Emit(IXamlILEmitter codegen); |
|
|
|
|
|
|
|
public abstract void Emit(IXamlILEmitter emitter); |
|
|
|
|
|
|
|
public abstract void EmitWithArguments( |
|
|
|
XamlEmitContextWithLocals<IXamlILEmitter, XamlILNodeEmitResult> context, |
|
|
|
IXamlILEmitter emitter, |
|
|
|
IReadOnlyList<IXamlAstValueNode> arguments); |
|
|
|
|
|
|
|
public bool Equals(AvaloniaPropertyCustomSetter other) |
|
|
|
{ |
|
|
|
if (ReferenceEquals(null, other)) |
|
|
|
return false; |
|
|
|
if (ReferenceEquals(this, other)) |
|
|
|
return true; |
|
|
|
|
|
|
|
return GetType() == other.GetType() && AvaloniaProperty.Equals(other.AvaloniaProperty); |
|
|
|
} |
|
|
|
|
|
|
|
public override bool Equals(object obj) |
|
|
|
=> Equals(obj as AvaloniaPropertyCustomSetter); |
|
|
|
|
|
|
|
public override int GetHashCode() |
|
|
|
=> AvaloniaProperty.GetHashCode(); |
|
|
|
} |
|
|
|
|
|
|
|
class BindingSetter : AvaloniaPropertyCustomSetter |
|
|
|
{ |
|
|
|
public BindingSetter(AvaloniaXamlIlWellKnownTypes types, |
|
|
|
IXamlType declaringType, |
|
|
|
IXamlField avaloniaProperty) : base(types, declaringType, avaloniaProperty) |
|
|
|
IXamlField avaloniaProperty) : base(types, declaringType, avaloniaProperty, false) |
|
|
|
{ |
|
|
|
Parameters = new[] {types.IBinding}; |
|
|
|
Parameters = new[] { types.IBinding }; |
|
|
|
} |
|
|
|
|
|
|
|
public override void Emit(IXamlILEmitter emitter) |
|
|
|
@ -246,10 +272,25 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions |
|
|
|
emitter |
|
|
|
.Stloc(bloc.Local) |
|
|
|
.Ldsfld(AvaloniaProperty) |
|
|
|
.Ldloc(bloc.Local) |
|
|
|
// TODO: provide anchor?
|
|
|
|
.Ldnull(); |
|
|
|
emitter.EmitCall(Types.AvaloniaObjectBindMethod, true); |
|
|
|
.Ldloc(bloc.Local); |
|
|
|
EmitAnchorAndBind(emitter); |
|
|
|
} |
|
|
|
|
|
|
|
public override void EmitWithArguments( |
|
|
|
XamlEmitContextWithLocals<IXamlILEmitter, XamlILNodeEmitResult> context, |
|
|
|
IXamlILEmitter emitter, |
|
|
|
IReadOnlyList<IXamlAstValueNode> arguments) |
|
|
|
{ |
|
|
|
emitter.Ldsfld(AvaloniaProperty); |
|
|
|
context.Emit(arguments[0], emitter, Parameters[0]); |
|
|
|
EmitAnchorAndBind(emitter); |
|
|
|
} |
|
|
|
|
|
|
|
private void EmitAnchorAndBind(IXamlILEmitter emitter) |
|
|
|
{ |
|
|
|
emitter |
|
|
|
.Ldnull() // TODO: provide anchor?
|
|
|
|
.EmitCall(Types.AvaloniaObjectBindMethod, true); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -257,7 +298,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions |
|
|
|
{ |
|
|
|
public BindingWithPrioritySetter(AvaloniaXamlIlWellKnownTypes types, |
|
|
|
IXamlType declaringType, |
|
|
|
IXamlField avaloniaProperty) : base(types, declaringType, avaloniaProperty) |
|
|
|
IXamlField avaloniaProperty) : base(types, declaringType, avaloniaProperty, false) |
|
|
|
{ |
|
|
|
Parameters = new[] { types.BindingPriority, types.IBinding }; |
|
|
|
} |
|
|
|
@ -265,15 +306,29 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions |
|
|
|
public override void Emit(IXamlILEmitter emitter) |
|
|
|
{ |
|
|
|
using (var bloc = emitter.LocalsPool.GetLocal(Types.IBinding)) |
|
|
|
using (var priorityLocal = emitter.LocalsPool.GetLocal(Types.Int)) |
|
|
|
emitter |
|
|
|
.Stloc(bloc.Local) |
|
|
|
.Stloc(priorityLocal.Local) |
|
|
|
.Pop() // ignore priority
|
|
|
|
.Ldsfld(AvaloniaProperty) |
|
|
|
.Ldloc(bloc.Local) |
|
|
|
// TODO: provide anchor?
|
|
|
|
.Ldnull(); |
|
|
|
emitter.EmitCall(Types.AvaloniaObjectBindMethod, true); |
|
|
|
.Ldloc(bloc.Local); |
|
|
|
EmitAnchorAndBind(emitter); |
|
|
|
} |
|
|
|
|
|
|
|
public override void EmitWithArguments( |
|
|
|
XamlEmitContextWithLocals<IXamlILEmitter, XamlILNodeEmitResult> context, |
|
|
|
IXamlILEmitter emitter, |
|
|
|
IReadOnlyList<IXamlAstValueNode> arguments) |
|
|
|
{ |
|
|
|
emitter.Ldsfld(AvaloniaProperty); |
|
|
|
context.Emit(arguments[1], emitter, Parameters[1]); |
|
|
|
EmitAnchorAndBind(emitter); |
|
|
|
} |
|
|
|
|
|
|
|
private void EmitAnchorAndBind(IXamlILEmitter emitter) |
|
|
|
{ |
|
|
|
emitter |
|
|
|
.Ldnull() // TODO: provide anchor?
|
|
|
|
.EmitCall(Types.AvaloniaObjectBindMethod, true); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -281,7 +336,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions |
|
|
|
{ |
|
|
|
public SetValueWithPrioritySetter(AvaloniaXamlIlWellKnownTypes types, IXamlType declaringType, IXamlField avaloniaProperty, |
|
|
|
IXamlType propertyType) |
|
|
|
: base(types, declaringType, avaloniaProperty) |
|
|
|
: base(types, declaringType, avaloniaProperty, propertyType.AcceptsNull()) |
|
|
|
{ |
|
|
|
Parameters = new[] { types.BindingPriority, propertyType }; |
|
|
|
} |
|
|
|
@ -295,9 +350,6 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions |
|
|
|
- value |
|
|
|
*/ |
|
|
|
|
|
|
|
var method = Types.AvaloniaObjectSetStyledPropertyValue |
|
|
|
.MakeGenericMethod(new[] { Parameters[1] }); |
|
|
|
|
|
|
|
using (var valueLocal = emitter.LocalsPool.GetLocal(Parameters[1])) |
|
|
|
using (var priorityLocal = emitter.LocalsPool.GetLocal(Types.Int)) |
|
|
|
emitter |
|
|
|
@ -305,25 +357,57 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions |
|
|
|
.Stloc(priorityLocal.Local) |
|
|
|
.Ldsfld(AvaloniaProperty) |
|
|
|
.Ldloc(valueLocal.Local) |
|
|
|
.Ldloc(priorityLocal.Local) |
|
|
|
.EmitCall(method, true); |
|
|
|
.Ldloc(priorityLocal.Local); |
|
|
|
|
|
|
|
EmitSetStyledPropertyValue(emitter); |
|
|
|
} |
|
|
|
|
|
|
|
public override void EmitWithArguments( |
|
|
|
XamlEmitContextWithLocals<IXamlILEmitter, XamlILNodeEmitResult> context, |
|
|
|
IXamlILEmitter emitter, |
|
|
|
IReadOnlyList<IXamlAstValueNode> arguments) |
|
|
|
{ |
|
|
|
emitter.Ldsfld(AvaloniaProperty); |
|
|
|
context.Emit(arguments[1], emitter, Parameters[1]); |
|
|
|
context.Emit(arguments[0], emitter, Parameters[0]); |
|
|
|
EmitSetStyledPropertyValue(emitter); |
|
|
|
} |
|
|
|
|
|
|
|
private void EmitSetStyledPropertyValue(IXamlILEmitter emitter) |
|
|
|
{ |
|
|
|
var method = Types.AvaloniaObjectSetStyledPropertyValue.MakeGenericMethod(new[] { Parameters[1] }); |
|
|
|
emitter.EmitCall(method, true); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
class UnsetValueSetter : AvaloniaPropertyCustomSetter |
|
|
|
{ |
|
|
|
public UnsetValueSetter(AvaloniaXamlIlWellKnownTypes types, IXamlType declaringType, IXamlField avaloniaProperty) |
|
|
|
: base(types, declaringType, avaloniaProperty) |
|
|
|
: base(types, declaringType, avaloniaProperty, false) |
|
|
|
{ |
|
|
|
Parameters = new[] {types.UnsetValueType}; |
|
|
|
Parameters = new[] { types.UnsetValueType }; |
|
|
|
} |
|
|
|
|
|
|
|
public override void Emit(IXamlILEmitter codegen) |
|
|
|
{ |
|
|
|
codegen.Pop(); |
|
|
|
EmitSetValue(codegen); |
|
|
|
} |
|
|
|
|
|
|
|
public override void EmitWithArguments( |
|
|
|
XamlEmitContextWithLocals<IXamlILEmitter, XamlILNodeEmitResult> context, |
|
|
|
IXamlILEmitter emitter, |
|
|
|
IReadOnlyList<IXamlAstValueNode> arguments) |
|
|
|
{ |
|
|
|
EmitSetValue(emitter); |
|
|
|
} |
|
|
|
|
|
|
|
private void EmitSetValue(IXamlILEmitter emitter) |
|
|
|
{ |
|
|
|
// Ignore the instance and load one from the static field to avoid extra local variable
|
|
|
|
var unsetValue = Types.AvaloniaProperty.Fields.First(f => f.Name == "UnsetValue"); |
|
|
|
codegen |
|
|
|
// Ignore the instance and load one from the static field to avoid extra local variable
|
|
|
|
.Pop() |
|
|
|
|
|
|
|
emitter |
|
|
|
.Ldsfld(AvaloniaProperty) |
|
|
|
.Ldsfld(unsetValue) |
|
|
|
.Ldc_I4(0) |
|
|
|
|