Browse Source

Updated XamlIl. Now even more static typing

pull/2322/head
Nikita Tsukanov 8 years ago
parent
commit
cfeeb5ed3f
  1. 1
      src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
  2. 2
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs
  3. 3
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlCompiler.cs
  4. 16
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs
  5. 66
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AddNameScopeRegistration.cs
  6. 8
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlAvaloniaPropertyResolver.cs
  7. 114
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlBindingPropertyAssignmentsTransformer.cs
  8. 2
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlSelectorTransformer.cs
  9. 51
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs
  10. 88
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlTransformInstanceAttachedProperties.cs
  11. 2
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlTransitionsTypeMetadataTransformer.cs
  12. 7
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs
  13. 113
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs
  14. 2
      src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github

1
src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj

@ -63,7 +63,6 @@
<Compile Include="XamlIl\CompilerExtensions\Transformers\AvaloniaXamlIlTransformInstanceAttachedProperties.cs" />
<Compile Include="XamlIl\CompilerExtensions\Transformers\AvaloniaXamlIlTransitionsTypeMetadataTransformer.cs" />
<Compile Include="XamlIl\CompilerExtensions\Transformers\AvaloniaXamlIlWellKnownTypes.cs" />
<Compile Include="XamlIl\CompilerExtensions\Transformers\AvaloniaXamlIlBindingPropertyAssignmentsTransformer.cs" />
<Compile Include="XamlIl\CompilerExtensions\XamlIlAvaloniaPropertyHelper.cs" />
<Compile Include="XamlIl\CompilerExtensions\AvaloniaXamlIlCompiler.cs" />
<Compile Include="XamlIl\CompilerExtensions\AvaloniaXamlIlLanguage.cs" />

2
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs

@ -33,7 +33,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
return ProvideTypedValue(serviceProvider);
}
public IBinding ProvideTypedValue(IServiceProvider serviceProvider)
public Binding ProvideTypedValue(IServiceProvider serviceProvider)
{
var descriptorContext = (ITypeDescriptorContext)serviceProvider;

3
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlCompiler.cs

@ -39,10 +39,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
InsertBefore<XamlIlPropertyReferenceResolver>(new AvaloniaXamlIlTransformInstanceAttachedProperties());
InsertAfter<XamlIlPropertyReferenceResolver>(new AvaloniaXamlIlAvaloniaPropertyResolver());
InsertBefore<XamlIlXamlPropertyValueTransformer>(new AvaloniaXamlIlBindingPropertyAssignmentsTransformer());
InsertBefore<XamlIlNewObjectTransformer>(
InsertBefore<XamlIlContentConvertTransformer>(
new AvaloniaXamlIlSelectorTransformer(),
new AvaloniaXamlIlSetterTransformer(),
new AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer(),

16
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/AvaloniaXamlIlLanguage.cs

@ -50,24 +50,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
typeSystem.GetType("Portable.Xaml.Markup.UsableDuringInitializationAttribute"),
typeSystem.GetType("Avalonia.Metadata.UsableDuringInitializationAttribute"),
},
MarkupExtensionCustomResultTypes =
{
bindingType,
typeSystem.GetType("Avalonia.UnsetValueType")
},
MarkupExtensionCustomResultHandler =
runtimeHelpers.FindMethod(m => m.Name == "ApplyNonMatchingMarkupExtensionV1"),
InnerServiceProviderFactoryMethod =
runtimeHelpers.FindMethod(m => m.Name == "CreateInnerServiceProviderV1"),
ShouldIgnoreMarkupExtensionCustomResultForProperty = (prop, customType) =>
{
if (prop.Name == "Value" && prop.Setter?.DeclaringType.FullName == "Avalonia.Styling.Setter")
return true;
if (customType.Equals(bindingType) &&
prop.CustomAttributes.Any(a => a.Type.Equals(assignBindingAttribute)))
return true;
return false;
},
ProvideValueTargetPropertyEmitter = XamlIlAvaloniaPropertyHelper.Emit,
};
rv.CustomAttributeResolver = new AttributeResolver(typeSystem, rv);

66
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AddNameScopeRegistration.cs

@ -1,4 +1,5 @@
using System;
using System.Linq;
using XamlIl.Ast;
using XamlIl.Transform;
using XamlIl.TypeSystem;
@ -11,21 +12,50 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
{
if (node is XamlIlPropertyAssignmentNode pa
&& pa.Property.Name == "Name"
&& pa.Property.Setter.DeclaringType.FullName == "Avalonia.StyledElement")
return new ScopeRegistrationNode(pa);
&& pa.Property.DeclaringType.FullName == "Avalonia.StyledElement")
{
if (context.ParentNodes().FirstOrDefault() is XamlIlManipulationGroupNode mg
&& mg.Children.OfType<ScopeRegistrationNode>().Any())
return node;
IXamlIlAstValueNode value = null;
for (var c = 0; c < pa.Values.Count; c++)
if (pa.Values[c].Type.GetClrType().Equals(context.Configuration.WellKnownTypes.String))
{
value = pa.Values[c];
if (!(value is XamlIlAstTextNode))
{
var local = new XamlIlAstCompilerLocalNode(value);
// Wrap original in local initialization
pa.Values[c] = new XamlIlAstLocalInitializationNodeEmitter(value, value, local);
// Use local
value = local;
}
break;
}
if (value != null)
return new XamlIlManipulationGroupNode(pa)
{
Children =
{
pa,
new ScopeRegistrationNode(value)
}
};
}
return node;
}
class ScopeRegistrationNode : XamlIlAstNode, IXamlIlAstManipulationNode, IXamlIlAstEmitableNode
{
private readonly IXamlIlType _targetType;
public IXamlIlAstValueNode Value { get; set; }
private IXamlIlProperty _property;
public ScopeRegistrationNode(XamlIlPropertyAssignmentNode pa) : base(pa)
public ScopeRegistrationNode(IXamlIlAstValueNode value) : base(value)
{
_property = pa.Property;
Value = pa.Value;
Value = value;
}
public override void VisitChildren(IXamlIlAstVisitor visitor)
@ -36,24 +66,13 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
var exts = context.Configuration.TypeSystem.GetType("Avalonia.Controls.NameScopeExtensions");
var findNameScope = exts.FindMethod(m => m.Name == "FindNameScope");
var registerMethod = findNameScope.ReturnType.FindMethod(m => m.Name == "Register");
using (var nameLoc = context.GetLocal(context.Configuration.WellKnownTypes.String))
using (var targetLoc = context.GetLocal(_property.Setter.DeclaringType))
using (var targetLoc = context.GetLocal(context.Configuration.WellKnownTypes.Object))
using (var nameScopeLoc = context.GetLocal(findNameScope.ReturnType))
{
var exit = codeGen.DefineLabel();
// var target = {target}
codeGen
.Castclass(_property.Setter.DeclaringType)
.Stloc(targetLoc.Local);
// var name = {EmitName()}
context.Emit(Value, codeGen, _property.PropertyType);
codeGen.Stloc(nameLoc.Local)
// target.Name = name
.Ldloc(targetLoc.Local)
.Ldloc(nameLoc.Local)
.EmitCall(_property.Setter)
// var target = {pop}
.Stloc(targetLoc.Local)
// var scope = target.FindNameScope()
.Ldloc(targetLoc.Local)
.Castclass(findNameScope.Parameters[0])
@ -62,8 +81,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
// if({scope} != null) goto call;
.Ldloc(nameScopeLoc.Local)
.Brfalse(exit)
.Ldloc(nameScopeLoc.Local)
.Ldloc(nameLoc.Local)
.Ldloc(nameScopeLoc.Local);
context.Emit(Value, codeGen, Value.Type.GetClrType());
codeGen
.Ldloc(targetLoc.Local)
.EmitCall(registerMethod)
.MarkLabel(exit);

8
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlAvaloniaPropertyResolver.cs

@ -8,14 +8,14 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
{
public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
{
if (node is XamlIlAstClrPropertyReference prop)
if (node is XamlIlAstClrProperty prop)
{
var n = prop.Property.Name + "Property";
var n = prop.Name + "Property";
var field =
(prop.Property.Getter ?? prop.Property.Setter).DeclaringType.Fields
prop.DeclaringType.Fields
.FirstOrDefault(f => f.Name == n);
if (field != null)
prop.Property = new XamlIlAvaloniaProperty(prop.Property, field);
return new XamlIlAvaloniaProperty(prop, field, context.GetAvaloniaTypes());
}
return node;

114
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlBindingPropertyAssignmentsTransformer.cs

@ -1,114 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using XamlIl.Ast;
using XamlIl.Transform;
using XamlIl.TypeSystem;
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
{
public class AvaloniaXamlIlBindingPropertyAssignmentsTransformer : IXamlIlAstTransformer
{
public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
{
if (node is XamlIlAstXamlPropertyValueNode pv
&& pv.Property.GetClrProperty() is IXamlIlAvaloniaProperty ap
&& pv.Values.Count == 1)
{
var types = context.GetAvaloniaTypes();
var vn = pv.Values[0];
if (vn.Type.GetClrType().Equals(XamlIlPseudoType.Null))
return node;
if (pv.Property.GetClrProperty().CustomAttributes
.Any(a => a.Type.Equals(types.AssignBindingAttribute)))
return node;
// Special handling for markup extensions
if (vn.Type.IsMarkupExtension)
{
if (XamlIlTransformHelpers
.GetMarkupExtensionProvideValueAlternatives(context, vn.Type.GetClrType())
.Any(x => types.IBinding.IsAssignableFrom(x.ReturnType)))
{
if (XamlIlTransformHelpers.TryConvertMarkupExtension(context, pv.Values[0],
new AssignBindingProperty(types, ap), out var ext))
return ext;
}
}
else if (types.IBinding.IsAssignableFrom(vn.Type.GetClrType()))
{
pv.Property = new XamlIlAstClrPropertyReference(pv.Property, new AssignBindingProperty(types, ap));
}
}
return node;
}
class AssignBindingProperty : IXamlIlAvaloniaProperty
{
public AssignBindingProperty(
AvaloniaXamlIlWellKnownTypes types,
IXamlIlAvaloniaProperty property
)
{
PropertyType = types.IBinding;
AvaloniaProperty = property.AvaloniaProperty;
CustomAttributes = property.CustomAttributes;
Name = property.Name;
Setter = new SetterMethod(types, (property.Setter ?? property.Getter).DeclaringType,
AvaloniaProperty);
}
public bool Equals(IXamlIlProperty other) =>
other is AssignBindingProperty abp && abp.AvaloniaProperty.Equals(AvaloniaProperty);
public string Name { get; }
public IXamlIlType PropertyType { get; }
public IXamlIlMethod Setter { get; }
public IXamlIlMethod Getter { get; }
public IReadOnlyList<IXamlIlCustomAttribute> CustomAttributes { get; }
public IXamlIlField AvaloniaProperty { get; }
class SetterMethod : IXamlIlCustomEmitMethod
{
private readonly AvaloniaXamlIlWellKnownTypes _types;
private readonly IXamlIlField _avaloniaProperty;
public SetterMethod(AvaloniaXamlIlWellKnownTypes types,
IXamlIlType declaringType,
IXamlIlField avaloniaProperty)
{
_types = types;
_avaloniaProperty = avaloniaProperty;
Parameters = new[] {types.AvaloniaObject, types.IBinding};
ReturnType = types.XamlIlTypes.Void;
DeclaringType = declaringType;
Name = "Bind_" + avaloniaProperty.Name;
}
public bool Equals(IXamlIlMethod other) =>
other is SetterMethod sm && sm._avaloniaProperty.Equals(_avaloniaProperty);
public string Name { get; }
public bool IsPublic => true;
public bool IsStatic => true;
public IXamlIlType ReturnType { get; }
public IReadOnlyList<IXamlIlType> Parameters { get; }
public IXamlIlType DeclaringType { get; }
public void EmitCall(IXamlIlEmitter emitter)
{
using (var bloc = emitter.LocalsPool.GetLocal(_types.IBinding))
emitter
.Stloc(bloc.Local)
.Ldsfld(_avaloniaProperty)
.Ldloc(bloc.Local)
// TODO: provide anchor?
.Ldnull();
emitter.EmitCall(_types.AvaloniaObjectBindMethod, true);
}
}
}
}
}

2
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlSelectorTransformer.cs

@ -34,7 +34,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
if (!(pn.Values[0] is XamlIlAstTextNode tn))
throw new XamlIlParseException("Selector property should be a text node", node);
var selectorType = pn.Property.GetClrProperty().PropertyType;
var selectorType = pn.Property.GetClrProperty().Getter.ReturnType;
var initialNode = new XamlIlSelectorInitialNode(node, selectorType);
XamlIlSelectorNode Create(IEnumerable<SelectorGrammar.ISyntax> syntax,
Func<string, string, XamlIlAstClrTypeReference> typeResolver)

51
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlSetterTransformer.cs

@ -53,21 +53,56 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
.OfType<XamlIlAstXamlPropertyValueNode>().FirstOrDefault(p => p.Property.GetClrProperty().Name == "Value");
if (valueProperty?.Values?.Count == 1 && valueProperty.Values[0] is XamlIlAstTextNode)
{
var propType = avaloniaPropertyNode.Property.Getter?.ReturnType
?? avaloniaPropertyNode.Property.Setters.First().Parameters[0];
if (!XamlIlTransformHelpers.TryGetCorrectlyTypedValue(context, valueProperty.Values[0],
avaloniaPropertyNode.Property.PropertyType, out var converted))
propType, out var converted))
throw new XamlIlParseException(
$"Unable to convert property value to {avaloniaPropertyNode.Property.PropertyType.GetFqn()}",
$"Unable to convert property value to {propType.GetFqn()}",
valueProperty.Values[0]);
valueProperty.Values = new List<IXamlIlAstValueNode>
{
new XamlIlAstRuntimeCastNode(converted, converted,
new XamlIlAstClrTypeReference(converted, context.Configuration.WellKnownTypes.Object, false))
};
valueProperty.Property = new SetterValueProperty(valueProperty.Property,
on.Type.GetClrType(), propType, context.GetAvaloniaTypes());
}
return node;
}
class SetterValueProperty : XamlIlAstClrProperty
{
public SetterValueProperty(IXamlIlLineInfo line, IXamlIlType setterType, IXamlIlType targetType,
AvaloniaXamlIlWellKnownTypes types)
: base(line, "Value", setterType, null)
{
Getter = setterType.Methods.First(m => m.Name == "get_Value");
var method = setterType.Methods.First(m => m.Name == "set_Value");
Setters.Add(new XamlIlDirectCallPropertySetter(method, types.IBinding));
Setters.Add(new XamlIlDirectCallPropertySetter(method, types.UnsetValueType));
Setters.Add(new XamlIlDirectCallPropertySetter(method, targetType));
}
class XamlIlDirectCallPropertySetter : IXamlIlPropertySetter
{
private readonly IXamlIlMethod _method;
private readonly IXamlIlType _type;
public IXamlIlType TargetType { get; }
public PropertySetterBinderParameters BinderParameters { get; } = new PropertySetterBinderParameters();
public IReadOnlyList<IXamlIlType> Parameters { get; }
public void Emit(IXamlIlEmitter codegen)
{
if (_type.IsValueType)
codegen.Box(_type);
codegen.EmitCall(_method, true);
}
public XamlIlDirectCallPropertySetter(IXamlIlMethod method, IXamlIlType type)
{
_method = method;
_type = type;
Parameters = new[] {type};
TargetType = method.ThisOrFirstParameter();
}
}
}
}
}

88
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlTransformInstanceAttachedProperties.cs

@ -56,10 +56,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
avaloniaPropertyType.GenericArguments[0] :
context.Configuration.WellKnownTypes.Object;
return new XamlIlAstClrPropertyReference(prop,
new AvaloniaAttachedInstanceProperty(prop.Name, context.Configuration,
return new AvaloniaAttachedInstanceProperty(prop, context.Configuration,
declaringType, propertyType, avaloniaPropertyType, avaloniaObject,
avaloniaPropertyField));
avaloniaPropertyField);
}
}
@ -71,7 +70,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
return node;
}
class AvaloniaAttachedInstanceProperty : IXamlIlAvaloniaProperty
class AvaloniaAttachedInstanceProperty : XamlIlAstClrProperty, IXamlIlAvaloniaProperty
{
private readonly XamlIlTransformerConfiguration _config;
private readonly IXamlIlType _declaringType;
@ -79,13 +78,16 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
private readonly IXamlIlType _avaloniaObject;
private readonly IXamlIlField _field;
public AvaloniaAttachedInstanceProperty(string name,
public AvaloniaAttachedInstanceProperty(XamlIlAstNamePropertyReference prop,
XamlIlTransformerConfiguration config,
IXamlIlType declaringType,
IXamlIlType type,
IXamlIlType avaloniaPropertyType,
IXamlIlType avaloniaObject,
IXamlIlField field)
IXamlIlField field) : base(prop, prop.Name,
declaringType, null)
{
_config = config;
_declaringType = declaringType;
@ -97,72 +99,50 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
_avaloniaObject = avaloniaObject;
_field = field;
Name = name;
PropertyType = type;
Setter = new SetterMethod(this);
Setters.Add(new SetterMethod(this));
Getter = new GetterMethod(this);
}
public IXamlIlField AvaloniaProperty => _field;
public bool Equals(IXamlIlProperty other) =>
other is AvaloniaAttachedInstanceProperty ap && ap._field.Equals(_field);
public string Name { get; }
public IXamlIlType PropertyType { get; }
public IXamlIlMethod Setter { get; }
public IXamlIlMethod Getter { get; }
public IReadOnlyList<IXamlIlCustomAttribute> CustomAttributes { get; } = new List<IXamlIlCustomAttribute>();
class Method
{
public AvaloniaAttachedInstanceProperty Parent { get; }
public bool IsPublic => true;
public bool IsStatic => true;
public string Name { get; protected set; }
public IXamlIlType DeclaringType { get; }
public Method(AvaloniaAttachedInstanceProperty parent)
{
Parent = parent;
DeclaringType = parent._declaringType;
}
public IXamlIlType PropertyType { get; }
public bool Equals(IXamlIlMethod other) =>
other is Method m && m.Name == Name && m.DeclaringType.Equals(DeclaringType);
}
public IXamlIlField AvaloniaProperty => _field;
class SetterMethod : Method, IXamlIlCustomEmitMethod
class SetterMethod : IXamlIlPropertySetter
{
public SetterMethod(AvaloniaAttachedInstanceProperty parent) : base(parent)
private readonly AvaloniaAttachedInstanceProperty _parent;
public SetterMethod(AvaloniaAttachedInstanceProperty parent)
{
Name = "AvaloniaObject:SetValue_" + Parent.Name;
Parameters = new[] {Parent._avaloniaObject, Parent.PropertyType};
_parent = parent;
Parameters = new[] {_parent._avaloniaObject, _parent.PropertyType};
}
public IXamlIlType ReturnType => Parent._config.WellKnownTypes.Void;
public IXamlIlType TargetType => _parent.DeclaringType;
public PropertySetterBinderParameters BinderParameters { get; } = new PropertySetterBinderParameters();
public IReadOnlyList<IXamlIlType> Parameters { get; }
public void EmitCall(IXamlIlEmitter emitter)
public void Emit(IXamlIlEmitter emitter)
{
var so = Parent._config.WellKnownTypes.Object;
var method = Parent._avaloniaObject
var so = _parent._config.WellKnownTypes.Object;
var method = _parent._avaloniaObject
.FindMethod(m => m.IsPublic && !m.IsStatic && m.Name == "SetValue"
&&
m.Parameters.Count == 3
&& m.Parameters[0].Equals(Parent._avaloniaPropertyType)
&& m.Parameters[0].Equals(_parent._avaloniaPropertyType)
&& m.Parameters[1].Equals(so)
&& m.Parameters[2].IsEnum
);
if (method == null)
throw new XamlIlTypeSystemException(
"Unable to find SetValue(AvaloniaProperty, object, BindingPriority) on AvaloniaObject");
using (var loc = emitter.LocalsPool.GetLocal(Parent.PropertyType))
using (var loc = emitter.LocalsPool.GetLocal(_parent.PropertyType))
emitter
.Stloc(loc.Local)
.Ldsfld(Parent._field)
.Ldsfld(_parent._field)
.Ldloc(loc.Local);
if(Parent.PropertyType.IsValueType)
emitter.Box(Parent.PropertyType);
if(_parent.PropertyType.IsValueType)
emitter.Box(_parent.PropertyType);
emitter
.Ldc_I4(0)
.EmitCall(method);
@ -170,14 +150,24 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
}
}
class GetterMethod : Method, IXamlIlCustomEmitMethod
class GetterMethod : IXamlIlCustomEmitMethod
{
public GetterMethod(AvaloniaAttachedInstanceProperty parent) : base(parent)
public GetterMethod(AvaloniaAttachedInstanceProperty parent)
{
Parent = parent;
DeclaringType = parent._declaringType;
Name = "AvaloniaObject:GetValue_" + Parent.Name;
Parameters = new[] {parent._avaloniaObject};
}
public AvaloniaAttachedInstanceProperty Parent { get; }
public bool IsPublic => true;
public bool IsStatic => true;
public string Name { get; protected set; }
public IXamlIlType DeclaringType { get; }
public bool Equals(IXamlIlMethod other) =>
other is GetterMethod m && m.Name == Name && m.DeclaringType.Equals(DeclaringType);
public IXamlIlType ReturnType => Parent.PropertyType;
public IReadOnlyList<IXamlIlType> Parameters { get; }
public void EmitCall(IXamlIlEmitter emitter)

2
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlTransitionsTypeMetadataTransformer.cs

@ -12,7 +12,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
foreach (var ch in on.Children)
{
if (ch is XamlIlAstXamlPropertyValueNode pn
&& pn.Property.GetClrProperty().PropertyType.Equals(context.GetAvaloniaTypes().Transitions))
&& pn.Property.GetClrProperty().Getter?.ReturnType.Equals(context.GetAvaloniaTypes().Transitions) == true)
{
for (var c = 0; c < pn.Values.Count; c++)
{

7
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs

@ -7,14 +7,17 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
{
public IXamlIlType AvaloniaObject { get; }
public IXamlIlType IAvaloniaObject { get; }
public IXamlIlType BindingPriority { get; }
public IXamlIlType AvaloniaObjectExtensions { get; }
public IXamlIlType AvaloniaProperty { get; }
public IXamlIlType IBinding { get; }
public IXamlIlMethod AvaloniaObjectBindMethod { get; }
public IXamlIlMethod AvaloniaObjectSetValueMethod { get; }
public IXamlIlType IDisposable { get; }
public XamlIlTypeWellKnownTypes XamlIlTypes { get; }
public IXamlIlType Transitions { get; }
public IXamlIlType AssignBindingAttribute { get; }
public IXamlIlType UnsetValueType { get; }
public AvaloniaXamlIlWellKnownTypes(XamlIlAstTransformationContext ctx)
{
@ -23,6 +26,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
IAvaloniaObject = ctx.Configuration.TypeSystem.GetType("Avalonia.IAvaloniaObject");
AvaloniaObjectExtensions = ctx.Configuration.TypeSystem.GetType("Avalonia.AvaloniaObjectExtensions");
AvaloniaProperty = ctx.Configuration.TypeSystem.GetType("Avalonia.AvaloniaProperty");
BindingPriority = ctx.Configuration.TypeSystem.GetType("Avalonia.Data.BindingPriority");
IBinding = ctx.Configuration.TypeSystem.GetType("Avalonia.Data.IBinding");
IDisposable = ctx.Configuration.TypeSystem.GetType("System.IDisposable");
Transitions = ctx.Configuration.TypeSystem.GetType("Avalonia.Animation.Transitions");
@ -30,6 +34,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
AvaloniaObjectBindMethod = AvaloniaObjectExtensions.FindMethod("Bind", IDisposable, false, IAvaloniaObject,
AvaloniaProperty,
IBinding, ctx.Configuration.WellKnownTypes.Object);
UnsetValueType = ctx.Configuration.TypeSystem.GetType("Avalonia.UnsetValueType");
AvaloniaObjectSetValueMethod = AvaloniaObject.FindMethod("SetValue", XamlIlTypes.Void,
false, AvaloniaProperty, XamlIlTypes.Object, BindingPriority);
}
}

113
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs

@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using Avalonia.Markup.Xaml.Parsers;
using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers;
using Avalonia.Utilities;
using XamlIl;
using XamlIl.Ast;
@ -13,13 +15,25 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
{
class XamlIlAvaloniaPropertyHelper
{
public static bool Emit(XamlIlEmitContext context, IXamlIlEmitter emitter, IXamlIlProperty property)
public static bool Emit(XamlIlEmitContext context, IXamlIlEmitter emitter, XamlIlAstClrProperty property)
{
if (property is IXamlIlAvaloniaProperty ap)
{
emitter.Ldsfld(ap.AvaloniaProperty);
return true;
}
var type = property.DeclaringType;
var name = property.Name + "Property";
var found = type.Fields.FirstOrDefault(f => f.IsStatic && f.Name == name);
if (found == null)
return false;
emitter.Ldsfld(found);
return true;
}
public static bool Emit(XamlIlEmitContext context, IXamlIlEmitter emitter, IXamlIlProperty property)
{
var type = (property.Getter ?? property.Setter).DeclaringType;
var name = property.Name + "Property";
var found = type.Fields.FirstOrDefault(f => f.IsStatic && f.Name == name);
@ -54,8 +68,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
}
var clrProperty =
((XamlIlAstClrPropertyReference)new XamlIlPropertyReferenceResolver().Transform(context,
forgedReference)).Property;
((XamlIlAstClrProperty)new XamlIlPropertyReferenceResolver().Transform(context,
forgedReference));
return new XamlIlAvaloniaPropertyNode(lineInfo,
context.Configuration.TypeSystem.GetType("Avalonia.AvaloniaProperty"),
clrProperty);
@ -64,13 +78,13 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
class XamlIlAvaloniaPropertyNode : XamlIlAstNode, IXamlIlAstValueNode, IXamlIlAstEmitableNode
{
public XamlIlAvaloniaPropertyNode(IXamlIlLineInfo lineInfo, IXamlIlType type, IXamlIlProperty property) : base(lineInfo)
public XamlIlAvaloniaPropertyNode(IXamlIlLineInfo lineInfo, IXamlIlType type, XamlIlAstClrProperty property) : base(lineInfo)
{
Type = new XamlIlAstClrTypeReference(this, type, false);
Property = property;
}
public IXamlIlProperty Property { get; }
public XamlIlAstClrProperty Property { get; }
public IXamlIlAstTypeReference Type { get; }
public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
@ -81,29 +95,92 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
}
}
interface IXamlIlAvaloniaProperty : IXamlIlProperty
interface IXamlIlAvaloniaProperty
{
IXamlIlField AvaloniaProperty { get; }
}
class XamlIlAvaloniaProperty : IXamlIlAvaloniaProperty
class XamlIlAvaloniaProperty : XamlIlAstClrProperty, IXamlIlAvaloniaProperty
{
private readonly IXamlIlProperty _original;
public IXamlIlField AvaloniaProperty { get; }
public XamlIlAvaloniaProperty(IXamlIlProperty original, IXamlIlField field)
public XamlIlAvaloniaProperty(XamlIlAstClrProperty original, IXamlIlField field,
AvaloniaXamlIlWellKnownTypes types)
:base(original, original.Name, original.DeclaringType, original.Getter, original.Setters)
{
_original = original;
AvaloniaProperty = field;
CustomAttributes = original.CustomAttributes;
if (!original.CustomAttributes.Any(ca => ca.Type.Equals(types.AssignBindingAttribute)))
Setters.Insert(0, new BindingSetter(types, original.DeclaringType, field));
Setters.Insert(0, new UnsetValueSetter(types, original.DeclaringType, field));
}
public bool Equals(IXamlIlProperty other) =>
other is XamlIlAvaloniaProperty p && p.AvaloniaProperty.Equals(AvaloniaProperty);
abstract class AvaloniaPropertyCustomSetter : IXamlIlPropertySetter
{
protected AvaloniaXamlIlWellKnownTypes Types;
protected IXamlIlField AvaloniaProperty;
public string Name => _original.Name;
public IXamlIlType PropertyType => _original.PropertyType;
public IXamlIlMethod Setter => _original.Setter;
public IXamlIlMethod Getter => _original.Getter;
public IReadOnlyList<IXamlIlCustomAttribute> CustomAttributes => _original.CustomAttributes;
public AvaloniaPropertyCustomSetter(AvaloniaXamlIlWellKnownTypes types,
IXamlIlType declaringType,
IXamlIlField avaloniaProperty)
{
Types = types;
AvaloniaProperty = avaloniaProperty;
TargetType = declaringType;
}
public IXamlIlType TargetType { get; }
public PropertySetterBinderParameters BinderParameters { get; } = new PropertySetterBinderParameters
{
AllowNull = false
};
public IReadOnlyList<IXamlIlType> Parameters { get; set; }
public abstract void Emit(IXamlIlEmitter codegen);
}
class BindingSetter : AvaloniaPropertyCustomSetter
{
public BindingSetter(AvaloniaXamlIlWellKnownTypes types,
IXamlIlType declaringType,
IXamlIlField avaloniaProperty) : base(types, declaringType, avaloniaProperty)
{
Parameters = new[] {types.IBinding};
}
public override void Emit(IXamlIlEmitter emitter)
{
using (var bloc = emitter.LocalsPool.GetLocal(Types.IBinding))
emitter
.Stloc(bloc.Local)
.Ldsfld(AvaloniaProperty)
.Ldloc(bloc.Local)
// TODO: provide anchor?
.Ldnull();
emitter.EmitCall(Types.AvaloniaObjectBindMethod, true);
}
}
class UnsetValueSetter : AvaloniaPropertyCustomSetter
{
public UnsetValueSetter(AvaloniaXamlIlWellKnownTypes types, IXamlIlType declaringType, IXamlIlField avaloniaProperty)
: base(types, declaringType, avaloniaProperty)
{
Parameters = new[] {types.UnsetValueType};
}
public override void Emit(IXamlIlEmitter codegen)
{
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()
.Ldsfld(AvaloniaProperty)
.Ldsfld(unsetValue)
.Ldc_I4(0)
.EmitCall(Types.AvaloniaObjectSetValueMethod, true);
}
}
}
}

2
src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github

@ -1 +1 @@
Subproject commit c0da3c49810316a96b47a00a83ae79d4f28406a1
Subproject commit 56c401c48f51979201ad810c96a9644705d4ddd9
Loading…
Cancel
Save