コード例 #1
0
        public static IXamlIlAvaloniaPropertyNode 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 tref = XamlIlTypeReferenceResolver.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 XamlIlParseException(
                              $"Unable to find {propertyFieldName} field on type {tref.Type.GetFullName()}", lineInfo);
                }
                return(new XamlIlAvaloniaPropertyFieldNode(context.GetAvaloniaTypes(), lineInfo, found));
            }

            var clrProperty =
                ((XamlIlAstClrProperty) new XamlIlPropertyReferenceResolver().Transform(context,
                                                                                        forgedReference));

            return(new XamlIlAvaloniaPropertyNode(lineInfo,
                                                  context.Configuration.TypeSystem.GetType("Avalonia.AvaloniaProperty"),
                                                  clrProperty));
        }
コード例 #2
0
        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 tref = XamlIlTypeReferenceResolver.ResolveType(context, xmlOwner, false, lineInfo, true);
                forgedReference = new XamlIlAstNamePropertyReference(lineInfo,
                                                                     tref, parsedPropertyName.name, tref);
            }

            var clrProperty =
                ((XamlIlAstClrProperty) new XamlIlPropertyReferenceResolver().Transform(context,
                                                                                        forgedReference));

            return(new XamlIlAvaloniaPropertyNode(lineInfo,
                                                  context.Configuration.TypeSystem.GetType("Avalonia.AvaloniaProperty"),
                                                  clrProperty));
        }
コード例 #3
0
        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
        {
            if (!(node is XamlIlAstObjectNode on && on.Type.GetClrType().FullName == "Avalonia.Styling.Style"))
            {
                return(node);
            }

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

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

            if (pn.Values.Count != 1)
            {
                throw new XamlIlParseException("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 XamlIlAstTextNode tn))
            {
                throw new XamlIlParseException("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, XamlIlAstClrTypeReference> 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 XamlIlParseException("Property selectors must be applied to a type.", node);
                        }

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

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

                        if (!XamlIlTransformHelpers.TryGetCorrectlyTypedValue(context,
                                                                              new XamlIlAstTextNode(node, property.Value, context.Configuration.WellKnownTypes.String),
                                                                              targetProperty.PropertyType, out var typedValue))
                        {
                            throw new XamlIlParseException(
                                      $"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.CommaSyntax comma:
                        if (results == null)
                        {
                            results = new XamlIlOrSelectorNode(node, selectorType);
                        }
                        results.Add(result);
                        result = initialNode;
                        break;

                    default:
                        throw new XamlIlParseException($"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 XamlIlParseException("Unable to parse selector: " + e.Message, node);
            }

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

            pn.Values[0] = selector;

            return(new AvaloniaXamlIlTargetTypeMetadataNode(on,
                                                            new XamlIlAstClrTypeReference(selector, selector.TargetType, false),
                                                            AvaloniaXamlIlTargetTypeMetadataNode.ScopeTypes.Style));
        }
コード例 #4
0
        public static bool TryConvertValue(XamlIlAstTransformationContext context,
                                           IXamlIlAstValueNode node, IXamlIlType type, XamlIlAstClrProperty propertyContext,
                                           out IXamlIlAstValueNode 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 XamlIlAstTextNode 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 = XamlIlTypeReferenceResolver.ResolveType(context, tn.Text, false, tn, true);
                    rv = new XamlIlTypeExtensionNode(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 XamlIlLoadMethodDelegateNode(tn, context.RootObject, type, handler);
                        return(true);
                    }
                }
            }

            IXamlIlAstValueNode CreateInvariantCulture() =>
            new XamlIlStaticOrTargetedReturnMethodCallNode(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 <IXamlIlAstValueNode> {
                    node
                };
                if (parser.Parameters.Count == 2)
                {
                    args.Add(CreateInvariantCulture());
                }

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

            if (cfg.TypeMappings.TypeDescriptorContext != null)
            {
                IXamlIlType 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 XamlIlAstNeedsParentStackValueNode(node,
                                                                new XamlIlAstRuntimeCastNode(node,
                                                                                             new XamlIlStaticOrTargetedReturnMethodCallNode(node, converterMethod,
                                                                                                                                            new[]
                    {
                        new XamlIlAstNewClrObjectNode(node,
                                                      new XamlIlAstClrTypeReference(node, converterType, false), null,
                                                      new List <IXamlIlAstValueNode>()),
                        new XamlIlAstContextLocalNode(node, cfg.TypeMappings.TypeDescriptorContext),
                        CreateInvariantCulture(), node
                    }), new XamlIlAstClrTypeReference(node, type, false)));
                    return(true);
                }
            }

            return(false);
        }