Exemplo n.º 1
0
        public static IXamlIlAvaloniaPropertyNode CreateNode(AstTransformationContext context,
                                                             string propertyName, IXamlAstTypeReference selectorTypeReference, IXamlLineInfo lineInfo)
        {
            XamlAstNamePropertyReference forgedReference;

            var parser = new PropertyParser();

            var parsedPropertyName = parser.Parse(new CharacterReader(propertyName.AsSpan()));

            if (parsedPropertyName.owner == null)
            {
                forgedReference = new XamlAstNamePropertyReference(lineInfo, selectorTypeReference,
                                                                   propertyName, selectorTypeReference);
            }
            else
            {
                var xmlOwner = parsedPropertyName.ns;
                if (xmlOwner != null)
                {
                    xmlOwner += ":";
                }
                xmlOwner += parsedPropertyName.owner;

                var tref = TypeReferenceResolver.ResolveType(context, xmlOwner, false, lineInfo, true);

                var propertyFieldName = parsedPropertyName.name + "Property";
                var found             = tref.Type.GetAllFields()
                                        .FirstOrDefault(f => f.IsStatic && f.IsPublic && f.Name == propertyFieldName);
                if (found == null)
                {
                    throw new XamlX.XamlParseException(
                              $"Unable to find {propertyFieldName} field on type {tref.Type.GetFullName()}", lineInfo);
                }
                return(new XamlIlAvaloniaPropertyFieldNode(context.GetAvaloniaTypes(), lineInfo, found));
            }

            var clrProperty =
                ((XamlAstClrProperty) new PropertyReferenceResolver().Transform(context,
                                                                                forgedReference));

            return(new XamlIlAvaloniaPropertyNode(lineInfo,
                                                  context.Configuration.TypeSystem.GetType("Avalonia.AvaloniaProperty"),
                                                  clrProperty));
        }
Exemplo n.º 2
0
        public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
        {
            if (!(node is XamlAstObjectNode on && on.Type.GetClrType().FullName == "Avalonia.Styling.ControlTheme"))
            {
                return(node);
            }

            // Check if we've already transformed this node.
            if (context.ParentNodes().FirstOrDefault() is AvaloniaXamlIlTargetTypeMetadataNode)
            {
                return(node);
            }

            var targetTypeNode = on.Children.OfType <XamlAstXamlPropertyValueNode>()
                                 .FirstOrDefault(p => p.Property.GetClrProperty().Name == "TargetType") ??
                                 throw new XamlParseException("ControlTheme must have a TargetType.", node);

            IXamlType targetType;

            if (targetTypeNode.Values[0] is XamlTypeExtensionNode extension)
            {
                targetType = extension.Value.GetClrType();
            }
            else if (targetTypeNode.Values[0] is XamlAstTextNode text)
            {
                targetType = TypeReferenceResolver.ResolveType(context, text.Text, false, text, true).GetClrType();
            }
            else
            {
                throw new XamlParseException("Could not determine TargetType for ControlTheme.", targetTypeNode);
            }

            return(new AvaloniaXamlIlTargetTypeMetadataNode(on,
                                                            new XamlAstClrTypeReference(targetTypeNode, targetType, false),
                                                            AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.Style));
        }
        private static BindingExpressionGrammar.INode ConvertLongFormPropertiesToBindingExpressionNode(
            AstTransformationContext context,
            XamlAstObjectNode binding)
        {
            BindingExpressionGrammar.INode convertedNode = null;

            var syntheticCompiledBindingProperties = binding.Children.OfType <XamlAstXamlPropertyValueNode>()
                                                     .Where(v => v.Property is AvaloniaSyntheticCompiledBindingProperty)
                                                     .ToList();

            var elementNameProperty = syntheticCompiledBindingProperties
                                      .FirstOrDefault(v =>
                                                      v.Property is AvaloniaSyntheticCompiledBindingProperty prop &&
                                                      prop.Name == SyntheticCompiledBindingPropertyName.ElementName);

            var sourceProperty = syntheticCompiledBindingProperties
                                 .FirstOrDefault(v =>
                                                 v.Property is AvaloniaSyntheticCompiledBindingProperty prop &&
                                                 prop.Name == SyntheticCompiledBindingPropertyName.Source);

            var relativeSourceProperty = syntheticCompiledBindingProperties
                                         .FirstOrDefault(v =>
                                                         v.Property is AvaloniaSyntheticCompiledBindingProperty prop &&
                                                         prop.Name == SyntheticCompiledBindingPropertyName.RelativeSource);

            if (elementNameProperty?.Values[0] is XamlAstTextNode elementName)
            {
                convertedNode = new BindingExpressionGrammar.NameNode {
                    Name = elementName.Text
                };
            }
            else if (elementNameProperty != null)
            {
                throw new XamlParseException($"Invalid ElementName '{elementNameProperty.Values[0]}'.", elementNameProperty.Values[0]);
            }

            if (sourceProperty?.Values[0] != null)
            {
                if (convertedNode != null)
                {
                    throw new XamlParseException("Only one of ElementName, Source, or RelativeSource specified as a binding source. Only one property is allowed.", binding);
                }

                convertedNode = new RawSourceBindingExpressionNode(sourceProperty?.Values[0]);
            }

            if (GetRelativeSourceObjectFromAssignment(
                    context,
                    relativeSourceProperty,
                    out var relativeSourceObject))
            {
                if (convertedNode != null)
                {
                    throw new XamlParseException("Only one of ElementName, Source, or RelativeSource specified as a binding source. Only one property is allowed.", binding);
                }

                var mode = relativeSourceObject.Children
                           .OfType <XamlAstXamlPropertyValueNode>()
                           .FirstOrDefault(x => x.Property.GetClrProperty().Name == "Mode")
                           ?.Values[0] is XamlAstTextNode modeAssignedValue ? modeAssignedValue.Text : null;
                if (relativeSourceObject.Arguments.Count == 0 && mode == null)
                {
                    mode = "FindAncestor";
                }

                if (mode == "FindAncestor")
                {
                    var ancestorLevel = relativeSourceObject.Children
                                        .OfType <XamlAstXamlPropertyValueNode>()
                                        .FirstOrDefault(x => x.Property.GetClrProperty().Name == "FindAncestor")
                                        ?.Values[0] is XamlAstTextNode ancestorLevelText?int.Parse(ancestorLevelText.Text) - 1 : 0;

                    var treeType = relativeSourceObject.Children
                                   .OfType <XamlAstXamlPropertyValueNode>()
                                   .FirstOrDefault(x => x.Property.GetClrProperty().Name == "Tree")
                                   ?.Values[0] is XamlAstTextNode treeTypeValue ? treeTypeValue.Text : "Visual";

                    var ancestorTypeName = relativeSourceObject.Children
                                           .OfType <XamlAstXamlPropertyValueNode>()
                                           .FirstOrDefault(x => x.Property.GetClrProperty().Name == "AncestorType")
                                           ?.Values[0] as XamlAstTextNode;

                    IXamlType ancestorType = null;
                    if (ancestorTypeName is null)
                    {
                        if (treeType == "Visual")
                        {
                            throw new XamlParseException("AncestorType must be set for RelativeSourceMode.FindAncestor when searching the visual tree.", relativeSourceObject);
                        }
                        else if (treeType == "Logical")
                        {
                            var styledElementType = context.GetAvaloniaTypes().StyledElement;
                            ancestorType = context
                                           .ParentNodes()
                                           .OfType <XamlAstObjectNode>()
                                           .Where(x => styledElementType.IsAssignableFrom(x.Type.GetClrType()))
                                           .ElementAtOrDefault(ancestorLevel)
                                           ?.Type.GetClrType();

                            if (ancestorType is null)
                            {
                                throw new XamlX.XamlParseException("Unable to resolve implicit ancestor type based on XAML tree.", relativeSourceObject);
                            }
                        }
                    }
                    else
                    {
                        ancestorType = TypeReferenceResolver.ResolveType(
                            context,
                            ancestorTypeName.Text,
                            false,
                            ancestorTypeName,
                            true).GetClrType();
                    }

                    if (treeType == "Visual")
                    {
                        convertedNode = new VisualAncestorBindingExpressionNode
                        {
                            Type  = ancestorType,
                            Level = ancestorLevel
                        };
                    }
                    else if (treeType == "Logical")
                    {
                        convertedNode = new LogicalAncestorBindingExpressionNode
                        {
                            Type  = ancestorType,
                            Level = ancestorLevel
                        };
                    }
                    else
                    {
                        throw new XamlParseException($"Unknown tree type '{treeType}'.", binding);
                    }
                }
                else if (mode == "DataContext")
                {
                    convertedNode = null;
                }
                else if (mode == "Self")
                {
                    convertedNode = new BindingExpressionGrammar.SelfNode();
                }
                else if (mode == "TemplatedParent")
                {
                    var parentType = context.ParentNodes().OfType <AvaloniaXamlIlTargetTypeMetadataNode>()
                                     .FirstOrDefault(x =>
                                                     x.ScopeType == AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.ControlTemplate)
                                     ?.TargetType.GetClrType();

                    if (parentType is null)
                    {
                        throw new XamlParseException("A binding with a TemplatedParent RelativeSource has to be in a ControlTemplate.", binding);
                    }

                    convertedNode = new TemplatedParentBindingExpressionNode {
                        Type = parentType
                    };
                }
                else
                {
                    throw new XamlParseException($"Unknown RelativeSource mode '{mode}'.", binding);
                }
            }

            if (elementNameProperty != null)
            {
                binding.Children.Remove(elementNameProperty);
            }
            if (sourceProperty != null)
            {
                binding.Children.Remove(sourceProperty);
            }
            if (relativeSourceProperty != null)
            {
                binding.Children.Remove(relativeSourceProperty);
            }

            return(convertedNode);
        }
        public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
        {
            if (context.ParentNodes().FirstOrDefault() is AvaloniaXamlIlDataContextTypeMetadataNode)
            {
                // We've already resolved the data context type for this node.
                return(node);
            }

            if (node is XamlAstConstructableObjectNode on)
            {
                AvaloniaXamlIlDataContextTypeMetadataNode inferredDataContextTypeNode  = null;
                AvaloniaXamlIlDataContextTypeMetadataNode directiveDataContextTypeNode = null;
                bool isDataTemplate = on.Type.GetClrType().Equals(context.GetAvaloniaTypes().DataTemplate);

                for (int i = 0; i < on.Children.Count; ++i)
                {
                    var child = on.Children[i];
                    if (child is XamlAstXmlDirective directive)
                    {
                        if (directive.Namespace == XamlNamespaces.Xaml2006 &&
                            directive.Name == "DataType" &&
                            directive.Values.Count == 1)
                        {
                            on.Children.RemoveAt(i);
                            i--;
                            if (directive.Values[0] is XamlAstTextNode text)
                            {
                                directiveDataContextTypeNode = new AvaloniaXamlIlDataContextTypeMetadataNode(on,
                                                                                                             TypeReferenceResolver.ResolveType(context, text.Text, isMarkupExtension: false, text, strict: true).Type);
                            }
                            else
                            {
                                throw new XamlX.XamlParseException("x:DataType should be set to a type name.", directive.Values[0]);
                            }
                        }
                    }
                    else if (child is XamlPropertyAssignmentNode pa)
                    {
                        if (pa.Property.Name == "DataContext" &&
                            pa.Property.DeclaringType.Equals(context.GetAvaloniaTypes().StyledElement) &&
                            pa.Values[0] is XamlMarkupExtensionNode ext &&
                            ext.Value is XamlAstConstructableObjectNode obj)
                        {
                            inferredDataContextTypeNode = ParseDataContext(context, on, obj);
                        }
                        else if (isDataTemplate &&
                                 pa.Property.Name == "DataType" &&
                                 pa.Values[0] is XamlTypeExtensionNode dataTypeNode)
                        {
                            inferredDataContextTypeNode = new AvaloniaXamlIlDataContextTypeMetadataNode(on, dataTypeNode.Value.GetClrType());
                        }
                    }
                }

                // If there is no x:DataType directive,
                // do more specialized inference
                if (directiveDataContextTypeNode is null)
                {
                    if (isDataTemplate && inferredDataContextTypeNode is null)
                    {
                        // Infer data type from collection binding on a control that displays items.
                        var parentObject = context.ParentNodes().OfType <XamlAstConstructableObjectNode>().FirstOrDefault();
                        if (parentObject != null && context.GetAvaloniaTypes().IItemsPresenterHost.IsDirectlyAssignableFrom(parentObject.Type.GetClrType()))
                        {
                            inferredDataContextTypeNode = InferDataContextOfPresentedItem(context, on, parentObject);
                        }
                        else
                        {
                            inferredDataContextTypeNode = new AvaloniaXamlIlUninferrableDataContextMetadataNode(on);
                        }
                    }
                }

                return(directiveDataContextTypeNode ?? inferredDataContextTypeNode ?? node);
            }
        public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
        {
            if (node is XamlAstXamlPropertyValueNode pv &&
                pv.Values.Count == 1 &&
                pv.Values[0] is XamlAstTextNode text &&
                pv.Property.GetClrProperty().Getter?.ReturnType
                .Equals(context.GetAvaloniaTypes().PropertyPath) == true
                )
            {
                var parentScope = context.ParentNodes().OfType <AvaloniaXamlIlTargetTypeMetadataNode>()
                                  .FirstOrDefault();
                if (parentScope == null)
                {
                    throw new XamlX.XamlParseException("No target type scope found for property path", text);
                }
                if (parentScope.ScopeType != AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.Style)
                {
                    throw new XamlX.XamlParseException("PropertyPath is currently only valid for styles", pv);
                }


                IEnumerable <PropertyPathGrammar.ISyntax> parsed;
                try
                {
                    parsed = PropertyPathGrammar.Parse(text.Text);
                }
                catch (Exception e)
                {
                    throw new XamlX.XamlParseException("Unable to parse PropertyPath: " + e.Message, text);
                }

                var       elements    = new List <IXamlIlPropertyPathElementNode>();
                IXamlType currentType = parentScope.TargetType.GetClrType();


                var expectProperty  = true;
                var expectCast      = true;
                var expectTraversal = false;
                var types           = context.GetAvaloniaTypes();

                IXamlType GetType(string ns, string name)
                {
                    return(TypeReferenceResolver.ResolveType(context, $"{ns}:{name}", false,
                                                             text, true).GetClrType());
                }

                void HandleProperty(string name, string typeNamespace, string typeName)
                {
                    if (!expectProperty || currentType == null)
                    {
                        throw new XamlX.XamlParseException("Unexpected property node", text);
                    }

                    var propertySearchType =
                        typeName != null?GetType(typeNamespace, typeName) : currentType;

                    IXamlIlPropertyPathElementNode prop = null;
                    var avaloniaPropertyFieldName       = name + "Property";
                    var avaloniaPropertyField           = propertySearchType.GetAllFields().FirstOrDefault(f =>
                                                                                                           f.IsStatic && f.IsPublic && f.Name == avaloniaPropertyFieldName);

                    if (avaloniaPropertyField != null)
                    {
                        prop = new XamlIlAvaloniaPropertyPropertyPathElementNode(avaloniaPropertyField,
                                                                                 XamlIlAvaloniaPropertyHelper.GetAvaloniaPropertyType(avaloniaPropertyField, types, text));
                    }
                    else
                    {
                        var clrProperty = propertySearchType.GetAllProperties().FirstOrDefault(p => p.Name == name);
                        prop = new XamlIClrPropertyPathElementNode(clrProperty);
                    }

                    if (prop == null)
                    {
                        throw new XamlX.XamlParseException(
                                  $"Unable to resolve property {name} on type {propertySearchType.GetFqn()}",
                                  text);
                    }

                    currentType = prop.Type;
                    elements.Add(prop);
                    expectProperty  = false;
                    expectTraversal = expectCast = true;
                }

                foreach (var ge in parsed)
                {
                    if (ge is PropertyPathGrammar.ChildTraversalSyntax)
                    {
                        if (!expectTraversal)
                        {
                            throw new XamlX.XamlParseException("Unexpected child traversal .", text);
                        }
                        elements.Add(new XamlIlChildTraversalPropertyPathElementNode());
                        expectTraversal = expectCast = false;
                        expectProperty  = true;
                    }
                    else if (ge is PropertyPathGrammar.EnsureTypeSyntax ets)
                    {
                        if (!expectCast)
                        {
                            throw new XamlX.XamlParseException("Unexpected cast node", text);
                        }
                        currentType = GetType(ets.TypeNamespace, ets.TypeName);
                        elements.Add(new XamlIlCastPropertyPathElementNode(currentType, true));
                        expectProperty = false;
                        expectCast     = expectTraversal = true;
                    }
                    else if (ge is PropertyPathGrammar.CastTypeSyntax cts)
                    {
                        if (!expectCast)
                        {
                            throw new XamlX.XamlParseException("Unexpected cast node", text);
                        }
                        //TODO: Check if cast can be done
                        currentType = GetType(cts.TypeNamespace, cts.TypeName);
                        elements.Add(new XamlIlCastPropertyPathElementNode(currentType, false));
                        expectProperty = false;
                        expectCast     = expectTraversal = true;
                    }
                    else if (ge is PropertyPathGrammar.PropertySyntax ps)
                    {
                        HandleProperty(ps.Name, null, null);
                    }
                    else if (ge is PropertyPathGrammar.TypeQualifiedPropertySyntax tqps)
                    {
                        HandleProperty(tqps.Name, tqps.TypeNamespace, tqps.TypeName);
                    }
                    else
                    {
                        throw new XamlX.XamlParseException("Unexpected node " + ge, text);
                    }
                }
                var propertyPathNode = new XamlIlPropertyPathNode(text, elements, types);
                if (propertyPathNode.Type == null)
                {
                    throw new XamlX.XamlParseException("Unexpected end of the property path", text);
                }
                pv.Values[0] = propertyPathNode;
            }

            return(node);
        }
Exemplo n.º 6
0
        public static bool TryConvertValue(AstTransformationContext context,
                                           IXamlAstValueNode node, IXamlType type, XamlAstClrProperty propertyContext,
                                           out IXamlAstValueNode rv)
        {
            rv = null;
            var cfg = context.Configuration;

            // Since we are doing a conversion anyway, it makes sense to check for the underlying nullable type
            if (type.GenericTypeDefinition?.Equals(cfg.WellKnownTypes.NullableT) == true)
            {
                type = type.GenericArguments[0];
            }


            if (cfg.CustomValueConverter?.Invoke(context, node, type, out rv) == true)
            {
                return(true);
            }

            var nodeType = node.Type.GetClrType();

            // Implicit type converters
            if (!nodeType.Equals(cfg.WellKnownTypes.String))
            {
                return(false);
            }

            if (node is XamlAstTextNode tn)
            {
                if (type.IsEnum)
                {
                    if (TypeSystemHelpers.TryGetEnumValueNode(type, tn.Text, tn, out var enumConstantNode))
                    {
                        rv = enumConstantNode;
                        return(true);
                    }
                }

                // Well known types
                if (TypeSystemHelpers.ParseConstantIfTypeAllows(tn.Text, type, tn, out var constantNode))
                {
                    rv = constantNode;
                    return(true);
                }

                if (type.FullName == "System.Type")
                {
                    var resolvedType = TypeReferenceResolver.ResolveType(context, tn.Text, false, tn, true);
                    rv = new XamlTypeExtensionNode(tn, resolvedType, type);
                    return(true);
                }

                if (cfg.WellKnownTypes.Delegate.IsAssignableFrom(type))
                {
                    var invoke   = type.FindMethod(m => m.Name == "Invoke");
                    var rootType = context.RootObject.Type.GetClrType();
                    var handler  =
                        rootType.FindMethod(tn.Text, invoke.ReturnType, false, invoke.Parameters.ToArray());
                    if (handler != null)
                    {
                        rv = new XamlLoadMethodDelegateNode(tn, context.RootObject, type, handler);
                        return(true);
                    }
                }
            }

            IXamlAstValueNode CreateInvariantCulture() =>
            new XamlStaticOrTargetedReturnMethodCallNode(node,
                                                         cfg.WellKnownTypes.CultureInfo.Methods.First(x =>
                                                                                                      x.IsPublic && x.IsStatic && x.Name == "get_InvariantCulture"), null);

            var candidates = type.Methods.Where(m => m.Name == "Parse" &&
                                                m.ReturnType.Equals(type) &&
                                                m.Parameters.Count > 0 &&
                                                m.Parameters[0].Equals(cfg.WellKnownTypes.String)).ToList();

            // Types with parse method
            var parser = candidates.FirstOrDefault(m =>
                                                   m.Parameters.Count == 2 &&
                                                   (
                                                       m.Parameters[1].Equals(cfg.WellKnownTypes.CultureInfo) ||
                                                       m.Parameters[1].Equals(cfg.WellKnownTypes.IFormatProvider)
                                                   )
                                                   )
                         ?? candidates.FirstOrDefault(m => m.Parameters.Count == 1);

            if (parser != null)
            {
                var args = new List <IXamlAstValueNode> {
                    node
                };
                if (parser.Parameters.Count == 2)
                {
                    args.Add(CreateInvariantCulture());
                }

                rv = new XamlStaticOrTargetedReturnMethodCallNode(node, parser, args);
                return(true);
            }

            if (cfg.TypeMappings.TypeDescriptorContext != null)
            {
                IXamlType converterType = null;
                if (propertyContext?.TypeConverters.TryGetValue(type, out converterType) != true)
                {
                    var typeConverterAttribute =
                        cfg.GetCustomAttribute(type, cfg.TypeMappings.TypeConverterAttributes).FirstOrDefault();
                    if (typeConverterAttribute != null)
                    {
                        converterType = TryGetTypeConverterFromCustomAttribute(cfg, typeConverterAttribute);
                    }
                }

                if (converterType != null)
                {
                    var converterMethod = converterType.FindMethod("ConvertFrom", cfg.WellKnownTypes.Object, false,
                                                                   cfg.TypeMappings.TypeDescriptorContext, cfg.WellKnownTypes.CultureInfo,
                                                                   cfg.WellKnownTypes.Object);
                    rv = new XamlAstNeedsParentStackValueNode(node,
                                                              new XamlAstRuntimeCastNode(node,
                                                                                         new XamlStaticOrTargetedReturnMethodCallNode(node, converterMethod,
                                                                                                                                      new[]
                    {
                        new XamlAstNewClrObjectNode(node,
                                                    new XamlAstClrTypeReference(node, converterType, false), null,
                                                    new List <IXamlAstValueNode>()),
                        new XamlAstContextLocalNode(node, cfg.TypeMappings.TypeDescriptorContext),
                        CreateInvariantCulture(), node
                    }), new XamlAstClrTypeReference(node, type, false)));
                    return(true);
                }
            }

            return(false);
        }
Exemplo n.º 7
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));
        }