10 changed files with 231 additions and 101 deletions
@ -1,21 +0,0 @@ |
|||||
using System.Linq; |
|
||||
using XamlIl.Transform; |
|
||||
using XamlIl.TypeSystem; |
|
||||
|
|
||||
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions |
|
||||
{ |
|
||||
public class AvaloniaPropertyDescriptorEmitter |
|
||||
{ |
|
||||
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); |
|
||||
if (found == null) |
|
||||
return false; |
|
||||
|
|
||||
emitter.Ldsfld(found); |
|
||||
return true; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,65 @@ |
|||||
|
using System.Linq; |
||||
|
using XamlIl.Ast; |
||||
|
using XamlIl.Transform; |
||||
|
using XamlIl.TypeSystem; |
||||
|
|
||||
|
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers |
||||
|
{ |
||||
|
class AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer : IXamlIlAstTransformer |
||||
|
{ |
||||
|
public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node) |
||||
|
{ |
||||
|
if (!(node is XamlIlAstObjectNode on |
||||
|
&& on.Type.GetClrType().FullName == "Avalonia.Markup.Xaml.Templates.ControlTemplate")) |
||||
|
return node; |
||||
|
var tt = on.Children.OfType<XamlIlAstXamlPropertyValueNode>().FirstOrDefault(ch => |
||||
|
ch.Property.GetClrProperty().Name == "TargetType"); |
||||
|
|
||||
|
if (context.ParentNodes().FirstOrDefault() is AvaloniaXamlIlTargetTypeMetadataNode) |
||||
|
// Deja vu. I've just been in this place before
|
||||
|
return node; |
||||
|
|
||||
|
IXamlIlAstTypeReference targetType; |
||||
|
|
||||
|
if ((tt?.Values.FirstOrDefault() is XamlIlTypeExtensionNode tn)) |
||||
|
{ |
||||
|
targetType = tn.Type; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
var parentScope = context.ParentNodes().OfType<AvaloniaXamlIlTargetTypeMetadataNode>() |
||||
|
.FirstOrDefault(); |
||||
|
if (parentScope?.Type == AvaloniaXamlIlTargetTypeMetadataNode.ScopeType.Style) |
||||
|
targetType = parentScope.TargetType; |
||||
|
else |
||||
|
targetType = new XamlIlAstClrTypeReference(node, |
||||
|
context.Configuration.TypeSystem.GetType("Avalonia.Controls.Control")); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
return new AvaloniaXamlIlTargetTypeMetadataNode(on, targetType, |
||||
|
AvaloniaXamlIlTargetTypeMetadataNode.ScopeType.ControlTemplate); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
class AvaloniaXamlIlTargetTypeMetadataNode : XamlIlValueWithSideEffectNodeBase |
||||
|
{ |
||||
|
public IXamlIlAstTypeReference TargetType { get; set; } |
||||
|
public ScopeType Type { get; } |
||||
|
|
||||
|
public enum ScopeType |
||||
|
{ |
||||
|
Style, |
||||
|
ControlTemplate |
||||
|
} |
||||
|
|
||||
|
public AvaloniaXamlIlTargetTypeMetadataNode(IXamlIlAstValueNode value, IXamlIlAstTypeReference targetType, |
||||
|
ScopeType type) |
||||
|
: base(value, value) |
||||
|
{ |
||||
|
TargetType = targetType; |
||||
|
Type = type; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
using System.Linq; |
||||
|
using XamlIl.Ast; |
||||
|
using XamlIl.Transform; |
||||
|
|
||||
|
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers |
||||
|
{ |
||||
|
public class AvaloniaXamlIlMetadataRemover : IXamlIlAstTransformer |
||||
|
{ |
||||
|
public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node) |
||||
|
{ |
||||
|
if (node is AvaloniaXamlIlTargetTypeMetadataNode md) |
||||
|
return md.Value; |
||||
|
|
||||
|
return node; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,79 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using Avalonia.Markup.Xaml.Parsers; |
||||
|
using Avalonia.Utilities; |
||||
|
using XamlIl; |
||||
|
using XamlIl.Ast; |
||||
|
using XamlIl.Transform; |
||||
|
using XamlIl.Transform.Transformers; |
||||
|
using XamlIl.TypeSystem; |
||||
|
|
||||
|
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions |
||||
|
{ |
||||
|
class XamlIlAvaloniaPropertyHelper |
||||
|
{ |
||||
|
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); |
||||
|
if (found == null) |
||||
|
return false; |
||||
|
|
||||
|
emitter.Ldsfld(found); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
public static XamlIlAvaloniaPropertyNode CreateNode(XamlIlAstTransformationContext context, |
||||
|
string propertyName, IXamlIlAstTypeReference selectorTypeReference, IXamlIlLineInfo lineInfo) |
||||
|
{ |
||||
|
XamlIlAstNamePropertyReference forgedReference; |
||||
|
|
||||
|
var parser = new PropertyParser(); |
||||
|
|
||||
|
var parsedPropertyName = parser.Parse(new CharacterReader(propertyName.AsSpan())); |
||||
|
if(parsedPropertyName.owner == null) |
||||
|
forgedReference = new XamlIlAstNamePropertyReference(lineInfo, selectorTypeReference, |
||||
|
propertyName, selectorTypeReference); |
||||
|
else |
||||
|
{ |
||||
|
var xmlOwner = parsedPropertyName.ns; |
||||
|
if (xmlOwner != null) |
||||
|
xmlOwner += ":"; |
||||
|
xmlOwner += parsedPropertyName.owner; |
||||
|
|
||||
|
var t = XamlIlTypeReferenceResolver.ResolveType(context, xmlOwner, lineInfo, true); |
||||
|
var tref = new XamlIlAstClrTypeReference(lineInfo, t); |
||||
|
forgedReference = new XamlIlAstNamePropertyReference(lineInfo, |
||||
|
tref, parsedPropertyName.name, tref); |
||||
|
} |
||||
|
|
||||
|
var clrProperty = |
||||
|
((XamlIlAstClrPropertyReference)new XamlIlPropertyReferenceResolver().Transform(context, |
||||
|
forgedReference)).Property; |
||||
|
return new XamlIlAvaloniaPropertyNode(lineInfo, |
||||
|
context.Configuration.TypeSystem.GetType("Avalonia.AvaloniaProperty"), |
||||
|
clrProperty); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
class XamlIlAvaloniaPropertyNode : XamlIlAstNode, IXamlIlAstValueNode, IXamlIlAstEmitableNode |
||||
|
{ |
||||
|
public XamlIlAvaloniaPropertyNode(IXamlIlLineInfo lineInfo, IXamlIlType type, IXamlIlProperty property) : base(lineInfo) |
||||
|
{ |
||||
|
Type = new XamlIlAstClrTypeReference(this, type); |
||||
|
Property = property; |
||||
|
} |
||||
|
|
||||
|
public IXamlIlProperty Property { get; } |
||||
|
|
||||
|
public IXamlIlAstTypeReference Type { get; } |
||||
|
public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen) |
||||
|
{ |
||||
|
if (!XamlIlAvaloniaPropertyHelper.Emit(context, codeGen, Property)) |
||||
|
throw new XamlIlLoadException(Property.Name + " is not an AvaloniaProperty", this); |
||||
|
return XamlIlNodeEmitResult.Type(0, Type.GetClrType()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue