Beispiel #1
0
        public XamlAstClrProperty(IXamlLineInfo lineInfo, IXamlProperty property,
                                  TransformerConfiguration cfg) : base(lineInfo)
        {
            Name   = property.Name;
            Getter = property.Getter;
            if (property.Setter != null)
            {
                Setters.Add(new XamlDirectCallPropertySetter(property.Setter));
            }
            CustomAttributes = property.CustomAttributes.ToList();
            DeclaringType    = (property.Getter ?? property.Setter)?.DeclaringType;
            var typeConverterAttributes = cfg.GetCustomAttribute(property, cfg.TypeMappings.TypeConverterAttributes);

            if (typeConverterAttributes != null)
            {
                foreach (var attr in typeConverterAttributes)
                {
                    var typeConverter =
                        XamlTransformHelpers.TryGetTypeConverterFromCustomAttribute(cfg, attr);
                    if (typeConverter != null)
                    {
                        TypeConverters[property.PropertyType] = typeConverter;
                        break;
                    }
                }
            }
        }
Beispiel #2
0
        public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
        {
            if (!(node is XamlAstObjectNode on))
            {
                return(node);
            }
            var nonDirectiveChildren = on.Children.Where(a => !(a is XamlAstXmlDirective)).ToList();

            if (on.Arguments.Count != 0 ||
                nonDirectiveChildren.Count != 1 ||
                !(nonDirectiveChildren[0] is IXamlAstValueNode vn) ||
                !vn.Type.GetClrType().Equals(context.Configuration.WellKnownTypes.String))
            {
                return(node);
            }

            if (XamlTransformHelpers.TryGetCorrectlyTypedValue(context, vn, on.Type.GetClrType(), out var rv))
            {
                if (nonDirectiveChildren.Count != on.Children.Count)
                {
                    rv = new XamlValueWithManipulationNode(rv, rv,
                                                           new XamlManipulationGroupNode(rv, on.Children.OfType <XamlAstXmlDirective>()));
                }
                return(rv);
            }

            if (on.Type.GetClrType().IsValueType)
            {
                throw new XamlLoadException(
                          $"Unable to convert value {(vn as XamlAstTextNode)?.Text}) to {on.Type.GetClrType()}", vn);
            }

            // Parser not found, isn't a value type, probably a regular object creation node with text content
            return(node);
        }
 public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
 {
     if (node is XamlAstClrProperty prop)
     {
         if (prop.DeclaringType.Assembly == context.GetWinUITypes().WinUIControlsAssembly)
         {
             IXamlField propertyIndexMaybe = context.GetWinUITypes().XamlPropertyIndex.Fields.FirstOrDefault(f => f.Name == $"{prop.DeclaringType.Name}_{prop.Name}");
             if (propertyIndexMaybe != null)
             {
                 prop.Setters.Insert(0, new XamlDirectSetter(context.GetWinUITypes(), prop.Getter.ReturnType, prop.DeclaringType, propertyIndexMaybe));
                 foreach (var adder in XamlTransformHelpers.FindPossibleAdders(context, prop.Getter.ReturnType))
                 {
                     if (adder.Parameters.Count == 1)
                     {
                         prop.Setters.Add(new XamlDirectAdderSetter(context.GetWinUITypes(), adder.Parameters[0], prop.DeclaringType, propertyIndexMaybe));
                     }
                 }
                 return(prop);
             }
             IXamlField eventIndexMaybe = context.GetWinUITypes().XamlEventIndex.Fields.FirstOrDefault(f => f.Name == $"{prop.DeclaringType.Name}_{prop.Name}");
             if (eventIndexMaybe != null)
             {
                 prop.Setters.Insert(0, new XamlDirectEventSetter(context.GetWinUITypes(), prop.Setters[0].Parameters[0], prop.DeclaringType, eventIndexMaybe));
                 return(prop);
             }
         }
     }
     return(node);
 }
Beispiel #4
0
        public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
        {
            if (node is XamlAstObjectNode ni)
            {
                XamlAstXamlPropertyValueNode propertyNode = null;

                for (var c = ni.Children.Count - 1; c >= 0; c--)
                {
                    var child = ni.Children[c];
                    if (child is IXamlAstValueNode valueNode)
                    {
                        if (propertyNode == null)
                        {
                            var contentProperty = context.Configuration.FindContentProperty(ni.Type.GetClrType());
                            if (contentProperty != null)
                            {
                                propertyNode = new XamlAstXamlPropertyValueNode(ni,
                                                                                new XamlAstClrProperty(ni, contentProperty, context.Configuration),
                                                                                Array.Empty <IXamlAstValueNode>());
                            }
                            else
                            {
                                var adders = XamlTransformHelpers.FindPossibleAdders(context, ni.Type.GetClrType());
                                if (adders.Count == 0)
                                {
                                    // If there's no content property, strip all whitespace-only nodes and continue
                                    WhitespaceNormalization.RemoveWhitespaceNodes(ni.Children);
                                    if (!ni.Children.Contains(child))
                                    {
                                        continue;
                                    }

                                    throw new XamlParseException(
                                              $"No Content property or any Add methods found for type {ni.Type.GetClrType().GetFqn()}",
                                              child);
                                }

                                propertyNode = new XamlAstXamlPropertyValueNode(ni, new XamlAstClrProperty(ni,
                                                                                                           "Content", ni.Type.GetClrType(), null,
                                                                                                           adders.Select(a => new XamlDirectCallPropertySetter(a)
                                {
                                    BinderParameters = { AllowMultiple = true }
                                })),
                                                                                Array.Empty <IXamlAstValueNode>());
                            }
                        }
                        // We are going in reverse order, so insert at the beginning
                        propertyNode.Values.Insert(0, valueNode);
                        ni.Children.RemoveAt(c);
                    }
                }

                if (propertyNode != null)
                {
                    ni.Children.Add(propertyNode);
                }
            }

            return(node);
        }
Beispiel #5
0
        public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
        {
            if (node is XamlAstClrProperty prop && prop.Getter != null)
            {
                foreach (var adder in XamlTransformHelpers.FindPossibleAdders(context, prop.Getter.ReturnType))
                {
                    prop.Setters.Add(new AdderSetter(prop.Getter, adder));
                }
            }

            return(node);
        }
Beispiel #6
0
        public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
        {
            if (!(node is XamlAstXamlPropertyValueNode propertyValueNode))
            {
                return(node);
            }

            if (!(propertyValueNode.Property is XamlAstClrProperty clrProperty))
            {
                return(node);
            }

            IEnumerable <IXamlCustomAttribute> attributes = propertyValueNode.Property.GetClrProperty().CustomAttributes;

            if (propertyValueNode.Property is XamlAstClrProperty referenceNode &&
                referenceNode.Getter != null)
            {
                attributes = attributes.Concat(referenceNode.Getter.CustomAttributes);
            }

            if (attributes.All(attribute => attribute.Type.FullName != "Avalonia.Controls.ResolveByNameAttribute"))
            {
                return(node);
            }

            if (propertyValueNode.Values.Count != 1 || !(propertyValueNode.Values.First() is XamlAstTextNode))
            {
                return(node);
            }

            var newNode = new XamlAstObjectNode(
                propertyValueNode.Values[0],
                new XamlAstClrTypeReference(propertyValueNode.Values[0],
                                            context.GetAvaloniaTypes().ResolveByNameExtension, true))
            {
                Arguments = new List <IXamlAstValueNode> {
                    propertyValueNode.Values[0]
                }
            };

            if (XamlTransformHelpers.TryConvertMarkupExtension(context, newNode, out var extensionNode))
            {
                propertyValueNode.Values[0] = extensionNode;
            }

            return(node);
        }
        public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
        {
            if (node is IXamlAstValueNode vn)
            {
                if (context.ParentNodes().FirstOrDefault() is XamlMarkupExtensionNode)
                {
                    return(node);
                }

                if (XamlTransformHelpers.TryConvertMarkupExtension(context, vn, out var rv))
                {
                    return(rv);
                }
            }

            return(node);
        }
        IXamlConstructor TransformArgumentsAndGetConstructor(
            AstTransformationContext context,
            XamlAstObjectNode n)
        {
            var type = n.Type.GetClrType();

            var argTypes = n.Arguments.Select(a => a.Type.GetClrType()).ToList();
            var ctor     = type.FindConstructor(argTypes);

            if (ctor == null)
            {
                if (argTypes.Count != 0)
                {
                    ctor = type.Constructors.FirstOrDefault(x =>
                                                            !x.IsStatic && x.IsPublic && x.Parameters.Count == argTypes.Count);
                }

                if (ctor == null)
                {
                    throw new XamlLoadException(
                              $"Unable to find public constructor for type {type.GetFqn()}({string.Join(", ", argTypes.Select(at => at.GetFqn()))})",
                              n);
                }
            }

            for (var c = 0; c < n.Arguments.Count; c++)
            {
                if (!XamlTransformHelpers.TryGetCorrectlyTypedValue(context, n.Arguments[c], ctor.Parameters[c], out var arg))
                {
                    throw new XamlLoadException(
                              $"Unable to convert {n.Arguments[c].Type.GetClrType().GetFqn()} to {ctor.Parameters[c].GetFqn()} for constructor of {n.Type.GetClrType().GetFqn()}",
                              n.Arguments[c]);
                }
                n.Arguments[c] = arg;
            }

            return(ctor);
        }
        private static IXamlIlBindingPathNode TransformBindingPath(AstTransformationContext context, IXamlLineInfo lineInfo, IXamlType startType, IEnumerable <BindingExpressionGrammar.INode> bindingExpression)
        {
            List <IXamlIlBindingPathElementNode> transformNodes = new List <IXamlIlBindingPathElementNode>();
            List <IXamlIlBindingPathElementNode> nodes          = new List <IXamlIlBindingPathElementNode>();

            foreach (var astNode in bindingExpression)
            {
                var targetType = nodes.Count == 0 ? startType : nodes[nodes.Count - 1].Type;
                switch (astNode)
                {
                case BindingExpressionGrammar.EmptyExpressionNode _:
                    break;

                case BindingExpressionGrammar.NotNode _:
                    transformNodes.Add(new XamlIlNotPathElementNode(context.Configuration.WellKnownTypes.Boolean));
                    break;

                case BindingExpressionGrammar.StreamNode _:
                    IXamlType observableType;
                    if (targetType.GenericTypeDefinition?.Equals(context.Configuration.TypeSystem.FindType("System.IObservable`1")) == true)
                    {
                        observableType = targetType;
                    }
                    else
                    {
                        observableType = targetType.GetAllInterfaces().FirstOrDefault(i => i.GenericTypeDefinition?.Equals(context.Configuration.TypeSystem.FindType("System.IObservable`1")) ?? false);
                    }

                    if (observableType != null)
                    {
                        nodes.Add(new XamlIlStreamObservablePathElementNode(observableType.GenericArguments[0]));
                        break;
                    }
                    bool foundTask = false;
                    for (var currentType = targetType; currentType != null; currentType = currentType.BaseType)
                    {
                        if (currentType.GenericTypeDefinition.Equals(context.Configuration.TypeSystem.GetType("System.Threading.Tasks.Task`1")))
                        {
                            foundTask = true;
                            nodes.Add(new XamlIlStreamTaskPathElementNode(currentType.GenericArguments[0]));
                            break;
                        }
                    }
                    if (foundTask)
                    {
                        break;
                    }
                    throw new XamlX.XamlParseException($"Compiled bindings do not support stream bindings for objects of type {targetType.FullName}.", lineInfo);

                case BindingExpressionGrammar.PropertyNameNode propName:
                    var avaloniaPropertyFieldNameMaybe = propName.PropertyName + "Property";
                    var avaloniaPropertyFieldMaybe     = targetType.GetAllFields().FirstOrDefault(f =>
                                                                                                  f.IsStatic && f.IsPublic && f.Name == avaloniaPropertyFieldNameMaybe);

                    if (avaloniaPropertyFieldMaybe != null)
                    {
                        nodes.Add(new XamlIlAvaloniaPropertyPropertyPathElementNode(avaloniaPropertyFieldMaybe,
                                                                                    XamlIlAvaloniaPropertyHelper.GetAvaloniaPropertyType(avaloniaPropertyFieldMaybe, context.GetAvaloniaTypes(), lineInfo)));
                    }
                    else
                    {
                        var clrProperty = targetType.GetAllProperties().FirstOrDefault(p => p.Name == propName.PropertyName);

                        if (clrProperty is null)
                        {
                            throw new XamlX.XamlParseException($"Unable to resolve property of name '{propName.PropertyName}' on type '{targetType}'.", lineInfo);
                        }
                        nodes.Add(new XamlIlClrPropertyPathElementNode(clrProperty));
                    }
                    break;

                case BindingExpressionGrammar.IndexerNode indexer:
                {
                    if (targetType.IsArray)
                    {
                        nodes.Add(new XamlIlArrayIndexerPathElementNode(targetType, indexer.Arguments, lineInfo));
                        break;
                    }

                    IXamlProperty property = null;
                    for (var currentType = targetType; currentType != null; currentType = currentType.BaseType)
                    {
                        var defaultMemberAttribute = currentType.CustomAttributes.FirstOrDefault(x => x.Type.Namespace == "System.Reflection" && x.Type.Name == "DefaultMemberAttribute");
                        if (defaultMemberAttribute != null)
                        {
                            property = targetType.GetAllProperties().FirstOrDefault(x => x.Name == (string)defaultMemberAttribute.Parameters[0]);
                            break;
                        }
                    }
                    ;
                    if (property is null)
                    {
                        throw new XamlX.XamlParseException($"The type '${targetType}' does not have an indexer.", lineInfo);
                    }

                    IEnumerable <IXamlType> parameters = property.IndexerParameters;

                    List <IXamlAstValueNode> values = new List <IXamlAstValueNode>();
                    int currentParamIndex           = 0;
                    foreach (var param in parameters)
                    {
                        var textNode = new XamlAstTextNode(lineInfo, indexer.Arguments[currentParamIndex], type: context.Configuration.WellKnownTypes.String);
                        if (!XamlTransformHelpers.TryGetCorrectlyTypedValue(context, textNode,
                                                                            param, out var converted))
                        {
                            throw new XamlX.XamlParseException(
                                      $"Unable to convert indexer parameter value of '{indexer.Arguments[currentParamIndex]}' to {param.GetFqn()}",
                                      textNode);
                        }

                        values.Add(converted);
                        currentParamIndex++;
                    }

                    bool isNotifyingCollection = targetType.GetAllInterfaces().Any(i => i.FullName == "System.Collections.Specialized.INotifyCollectionChanged");

                    nodes.Add(new XamlIlClrIndexerPathElementNode(property, values, string.Join(",", indexer.Arguments), isNotifyingCollection));
                    break;
                }

                case BindingExpressionGrammar.AttachedPropertyNameNode attachedProp:
                    var avaloniaPropertyFieldName = attachedProp.PropertyName + "Property";
                    var avaloniaPropertyField     = GetType(attachedProp.Namespace, attachedProp.TypeName).GetAllFields().FirstOrDefault(f =>
                                                                                                                                         f.IsStatic && f.IsPublic && f.Name == avaloniaPropertyFieldName);
                    nodes.Add(new XamlIlAvaloniaPropertyPropertyPathElementNode(avaloniaPropertyField,
                                                                                XamlIlAvaloniaPropertyHelper.GetAvaloniaPropertyType(avaloniaPropertyField, context.GetAvaloniaTypes(), lineInfo)));
                    break;

                case BindingExpressionGrammar.SelfNode _:
                    nodes.Add(new SelfPathElementNode(targetType));
                    break;

                case VisualAncestorBindingExpressionNode visualAncestor:
                    nodes.Add(new FindVisualAncestorPathElementNode(visualAncestor.Type, visualAncestor.Level));
                    break;

                case TemplatedParentBindingExpressionNode templatedParent:
                    var templatedParentField = context.GetAvaloniaTypes().StyledElement.GetAllFields()
                                               .FirstOrDefault(f => f.IsStatic && f.IsPublic && f.Name == "TemplatedParentProperty");
                    nodes.Add(new XamlIlAvaloniaPropertyPropertyPathElementNode(
                                  templatedParentField,
                                  templatedParent.Type));
                    break;

                case BindingExpressionGrammar.AncestorNode ancestor:
                    if (ancestor.Namespace is null && ancestor.TypeName is null)
                    {
                        var styledElementType = context.GetAvaloniaTypes().StyledElement;
                        var ancestorType      = context
                                                .ParentNodes()
                                                .OfType <XamlAstConstructableObjectNode>()
                                                .Where(x => styledElementType.IsAssignableFrom(x.Type.GetClrType()))
                                                .ElementAtOrDefault(ancestor.Level)
                                                ?.Type.GetClrType();

                        if (ancestorType is null)
                        {
                            throw new XamlX.XamlParseException("Unable to resolve implicit ancestor type based on XAML tree.", lineInfo);
                        }

                        nodes.Add(new FindAncestorPathElementNode(ancestorType, ancestor.Level));
                    }
                    else
                    {
                        nodes.Add(new FindAncestorPathElementNode(GetType(ancestor.Namespace, ancestor.TypeName), ancestor.Level));
                    }
                    break;
Beispiel #10
0
        public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
        {
            if (node is XamlAstXamlPropertyValueNode valueNode)
            {
                var property    = valueNode.Property.GetClrProperty();
                var assignments = new List <XamlPropertyAssignmentNode>();

                WhitespaceNormalization.RemoveWhitespaceNodes(valueNode.Values);

                foreach (var v in valueNode.Values)
                {
                    var keyNode   = FindAndRemoveKey(v);
                    var arguments = new List <IXamlAstValueNode>();

                    if (keyNode != null)
                    {
                        arguments.Add(keyNode);
                    }
                    arguments.Add(v);


                    // Pre-filter setters by non-last argument
                    var filteredSetters = property.Setters.Where(s => s.Parameters.Count == arguments.Count)
                                          .ToList();

                    if (arguments.Count > 1)
                    {
                        for (var c = 0; c < arguments.Count - 1; c++)
                        {
                            IXamlType convertedTo = null;
                            for (var s = 0; s < filteredSetters.Count;)
                            {
                                var setter = filteredSetters[s];
                                if (convertedTo == null)
                                {
                                    if (!XamlTransformHelpers.TryGetCorrectlyTypedValue(context, arguments[c],
                                                                                        setter.Parameters[c], out var converted))
                                    {
                                        filteredSetters.RemoveAt(c);
                                        continue;
                                    }
                                    else
                                    {
                                        convertedTo  = converted.Type.GetClrType();
                                        arguments[c] = converted;
                                    }
                                }
                                else
                                {
                                    if (!setter.Parameters[c].IsAssignableFrom(convertedTo))
                                    {
                                        throw new XamlLoadException(
                                                  $"Runtime setter selection is not supported for non-last setter arguments (e. g. x:Key) and can not downcast argument {c} of the setter from {convertedTo} to {setter.Parameters[c]}",
                                                  arguments[c]);
                                    }
                                }
                                s++;
                            }
                        }
                    }

                    XamlPropertyAssignmentNode CreateAssignment()
                    {
                        var matchedSetters = new List <IXamlPropertySetter>();

                        foreach (var setter in filteredSetters)
                        {
                            bool CanAssign(IXamlAstValueNode value, IXamlType type)
                            {
                                // Don't allow x:Null
                                if (!setter.BinderParameters.AllowXNull &&
                                    XamlPseudoType.Null.Equals(value.Type.GetClrType()))
                                {
                                    return(false);
                                }

                                // Direct cast
                                if (type.IsAssignableFrom(value.Type.GetClrType()))
                                {
                                    return(true);
                                }

                                // Upcast from System.Object
                                if (value.Type.GetClrType().Equals(context.Configuration.WellKnownTypes.Object))
                                {
                                    return(true);
                                }

                                return(false);
                            }

                            var valueArgIndex = arguments.Count - 1;
                            var valueArg      = arguments[valueArgIndex];
                            var setterType    = setter.Parameters[valueArgIndex];

                            if (CanAssign(valueArg, setterType))
                            {
                                matchedSetters.Add(setter);
                            }
                            // Converted value have more priority than custom setters, so we just create a setter without an alternative
                            else if (XamlTransformHelpers.TryConvertValue(context, valueArg, setterType, property,
                                                                          out var converted))
                            {
                                arguments[valueArgIndex] = converted;
                                return(new XamlPropertyAssignmentNode(valueNode,
                                                                      property, new[] { setter }, arguments));
                            }
                        }

                        if (matchedSetters.Count > 0)
                        {
                            return(new XamlPropertyAssignmentNode(v, property, matchedSetters, arguments));
                        }

                        throw new XamlLoadException(
                                  $"Unable to find suitable setter or adder for property {property.Name} of type {property.DeclaringType.GetFqn()} for argument {v.Type.GetClrType().GetFqn()}"
                                  + (keyNode != null ? $" and x:Key of type {keyNode.Type.GetClrType()}" : null)
                                  + ", available setter parameter lists are:\n" + string.Join("\n",
                                                                                              filteredSetters.Select(setter =>
                                                                                                                     string.Join(", ", setter.Parameters.Select(p => p.FullName))))
                                  , v);
                    }

                    assignments.Add(CreateAssignment());
                }

                if (assignments.Count == 1)
                {
                    return(assignments[0]);
                }

                if (assignments.Count > 1)
                {
                    // Skip the first one, since we only care about further setters, e. g. the following is perfectly valid:
                    // <Foo.Bar>
                    //   <SomeList/>
                    //   <ListItem/>
                    //   <ListItem/>
                    // </Foo.Bar>
                    // <SomeList/> would be foo.Bar = new SomeList() and <ListItem/> would be foo.Bar.Add(new ListItem());
                    foreach (var ass in assignments.Skip(1))
                    {
                        ass.PossibleSetters = ass.PossibleSetters.Where(s => s.BinderParameters.AllowMultiple).ToList();
                        if (ass.PossibleSetters.Count == 0)
                        {
                            throw new XamlLoadException(
                                      $"Unable to find a setter that allows multiple assignments to the property {ass.Property.Name} of type {ass.Property.DeclaringType.GetFqn()}",
                                      node);
                        }
                    }
                }

                return(new XamlManipulationGroupNode(valueNode, assignments));
            }

            return(node);
        }
Beispiel #11
0
        public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
        {
            if (!(node is XamlAstObjectNode on && on.Type.GetClrType().FullName == "Avalonia.Styling.Style"))
            {
                return(node);
            }

            var pn = on.Children.OfType <XamlAstXamlPropertyValueNode>()
                     .FirstOrDefault(p => p.Property.GetClrProperty().Name == "Selector");

            if (pn == null)
            {
                return(node);
            }

            if (pn.Values.Count != 1)
            {
                throw new XamlParseException("Selector property should should have exactly one value", node);
            }

            if (pn.Values[0] is XamlIlSelectorNode)
            {
                //Deja vu. I've just been in this place before
                return(node);
            }

            if (!(pn.Values[0] is XamlAstTextNode tn))
            {
                throw new XamlParseException("Selector property should be a text node", node);
            }

            var selectorType = pn.Property.GetClrProperty().Getter.ReturnType;
            var initialNode  = new XamlIlSelectorInitialNode(node, selectorType);

            XamlIlSelectorNode Create(IEnumerable <SelectorGrammar.ISyntax> syntax,
                                      Func <string, string, XamlAstClrTypeReference> typeResolver)
            {
                XamlIlSelectorNode   result  = initialNode;
                XamlIlOrSelectorNode results = null;

                foreach (var i in syntax)
                {
                    switch (i)
                    {
                    case SelectorGrammar.OfTypeSyntax ofType:
                        result = new XamlIlTypeSelector(result, typeResolver(ofType.Xmlns, ofType.TypeName).Type, true);
                        break;

                    case SelectorGrammar.IsSyntax @is:
                        result = new XamlIlTypeSelector(result, typeResolver(@is.Xmlns, @is.TypeName).Type, false);
                        break;

                    case SelectorGrammar.ClassSyntax @class:
                        result = new XamlIlStringSelector(result, XamlIlStringSelector.SelectorType.Class, @class.Class);
                        break;

                    case SelectorGrammar.NameSyntax name:
                        result = new XamlIlStringSelector(result, XamlIlStringSelector.SelectorType.Name, name.Name);
                        break;

                    case SelectorGrammar.PropertySyntax property:
                    {
                        var type = result?.TargetType;

                        if (type == null)
                        {
                            throw new XamlParseException("Property selectors must be applied to a type.", node);
                        }

                        var targetProperty =
                            type.GetAllProperties().FirstOrDefault(p => p.Name == property.Property);

                        if (targetProperty == null)
                        {
                            throw new XamlParseException($"Cannot find '{property.Property}' on '{type}", node);
                        }

                        if (!XamlTransformHelpers.TryGetCorrectlyTypedValue(context,
                                                                            new XamlAstTextNode(node, property.Value, context.Configuration.WellKnownTypes.String),
                                                                            targetProperty.PropertyType, out var typedValue))
                        {
                            throw new XamlParseException(
                                      $"Cannot convert '{property.Value}' to '{targetProperty.PropertyType.GetFqn()}",
                                      node);
                        }

                        result = new XamlIlPropertyEqualsSelector(result, targetProperty, typedValue);
                        break;
                    }

                    case SelectorGrammar.ChildSyntax child:
                        result = new XamlIlCombinatorSelector(result, XamlIlCombinatorSelector.SelectorType.Child);
                        break;

                    case SelectorGrammar.DescendantSyntax descendant:
                        result = new XamlIlCombinatorSelector(result, XamlIlCombinatorSelector.SelectorType.Descendant);
                        break;

                    case SelectorGrammar.TemplateSyntax template:
                        result = new XamlIlCombinatorSelector(result, XamlIlCombinatorSelector.SelectorType.Template);
                        break;

                    case SelectorGrammar.NotSyntax not:
                        result = new XamlIlNotSelector(result, Create(not.Argument, typeResolver));
                        break;

                    case SelectorGrammar.NthChildSyntax nth:
                        result = new XamlIlNthChildSelector(result, nth.Step, nth.Offset, XamlIlNthChildSelector.SelectorType.NthChild);
                        break;

                    case SelectorGrammar.NthLastChildSyntax nth:
                        result = new XamlIlNthChildSelector(result, nth.Step, nth.Offset, XamlIlNthChildSelector.SelectorType.NthLastChild);
                        break;

                    case SelectorGrammar.CommaSyntax comma:
                        if (results == null)
                        {
                            results = new XamlIlOrSelectorNode(node, selectorType);
                        }
                        results.Add(result);
                        result = initialNode;
                        break;

                    default:
                        throw new XamlParseException($"Unsupported selector grammar '{i.GetType()}'.", node);
                    }
                }

                if (results != null && result != null)
                {
                    results.Add(result);
                }

                return(results ?? result);
            }

            IEnumerable <SelectorGrammar.ISyntax> parsed;

            try
            {
                parsed = SelectorGrammar.Parse(tn.Text);
            }
            catch (Exception e)
            {
                throw new XamlParseException("Unable to parse selector: " + e.Message, node);
            }

            var selector = Create(parsed, (p, n)
                                  => TypeReferenceResolver.ResolveType(context, $"{p}:{n}", true, node, true));

            pn.Values[0] = selector;

            return(new AvaloniaXamlIlTargetTypeMetadataNode(on,
                                                            new XamlAstClrTypeReference(selector, selector.TargetType, false),
                                                            AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.Style));
        }