Exemplo n.º 1
0
        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
        {
            if (!(node is XamlIlAstObjectNode on))
            {
                return(node);
            }
            var nonDirectiveChildren = on.Children.Where(a => !(a is XamlIlAstXmlDirective)).ToList();

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

            if (XamlIlTransformHelpers.TryGetCorrectlyTypedValue(context, vn, on.Type.GetClrType(), out var rv))
            {
                if (nonDirectiveChildren.Count != on.Children.Count)
                {
                    rv = new XamlIlValueWithManipulationNode(rv, rv,
                                                             new XamlIlManipulationGroupNode(rv, on.Children.OfType <XamlIlAstXmlDirective>()));
                }
                return(rv);
            }

            if (on.Type.GetClrType().IsValueType)
            {
                throw new XamlIlLoadException(
                          $"Unable to convert value {(vn as XamlIlAstTextNode)?.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);
        }
Exemplo n.º 2
0
        public XamlIlAstClrProperty(IXamlIlLineInfo lineInfo, IXamlIlProperty property,
                                    XamlIlTransformerConfiguration cfg) : base(lineInfo)
        {
            Name   = property.Name;
            Getter = property.Getter;
            if (property.Setter != null)
            {
                Setters.Add(new XamlIlDirectCallPropertySetter(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 =
                        XamlIlTransformHelpers.TryGetTypeConverterFromCustomAttribute(cfg, attr);
                    if (typeConverter != null)
                    {
                        TypeConverters[property.PropertyType] = typeConverter;
                        break;
                    }
                }
            }
        }
        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
        {
            if (node is XamlIlAstClrProperty prop && prop.Getter != null)
            {
                foreach (var adder in XamlIlTransformHelpers.FindPossibleAdders(context, prop.Getter.ReturnType))
                {
                    prop.Setters.Add(new AdderSetter(prop.Getter, adder));
                }
            }

            return(node);
        }
Exemplo n.º 4
0
        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
        {
            if (node is XamlIlAstObjectNode ni)
            {
                XamlIlAstXamlPropertyValueNode propertyNode = null;

                for (var c = ni.Children.Count - 1; c >= 0; c--)
                {
                    var child = ni.Children[c];
                    if (child is IXamlIlAstValueNode valueNode)
                    {
                        if (propertyNode == null)
                        {
                            var contentProperty = context.Configuration.FindContentProperty(ni.Type.GetClrType());
                            if (contentProperty != null)
                            {
                                propertyNode = new XamlIlAstXamlPropertyValueNode(ni,
                                                                                  new XamlIlAstClrProperty(ni, contentProperty, context.Configuration),
                                                                                  Array.Empty <IXamlIlAstValueNode>());
                            }
                            else
                            {
                                var adders = XamlIlTransformHelpers.FindPossibleAdders(context, ni.Type.GetClrType());
                                if (adders.Count == 0)
                                {
                                    throw new XamlIlParseException(
                                              $"No Content property or any Add methods found for type {ni.Type.GetClrType().GetFqn()}",
                                              child);
                                }
                                propertyNode = new XamlIlAstXamlPropertyValueNode(ni, new XamlIlAstClrProperty(ni,
                                                                                                               "Content", ni.Type.GetClrType(), null,
                                                                                                               adders.Select(a => new XamlIlDirectCallPropertySetter(a)
                                {
                                    BinderParameters = { AllowMultiple = true }
                                })),
                                                                                  Array.Empty <IXamlIlAstValueNode>());
                            }
                        }
                        // 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);
        }
 public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
 {
     if (node is XamlIlAstXamlPropertyValueNode pn)
     {
         var assignments = XamlIlTransformHelpers.GeneratePropertyAssignments(context,
                                                                              pn.Property.GetClrProperty(),
                                                                              pn.Values);
         return(new XamlIlManipulationGroupNode(pn)
         {
             Children = assignments
         });
     }
     else
     {
         return(node);
     }
 }
Exemplo n.º 6
0
        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
        {
            if (node is IXamlIlAstValueNode vn)
            {
                if (context.ParentNodes().FirstOrDefault() is XamlIlMarkupExtensionNode)
                {
                    return(node);
                }

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

            return(node);
        }
        void SubTransform(XamlIlAstTransformationContext context, XamlIlAstObjectNode ni)
        {
            var valueIndexes = new List <int>();

            for (var c = 0; c < ni.Children.Count; c++)
            {
                if (ni.Children[c] is IXamlIlAstValueNode)
                {
                    valueIndexes.Add(c);
                }
            }

            if (valueIndexes.Count == 0)
            {
                return;
            }
            var type = ni.Type.GetClrType();

            IXamlIlAstValueNode VNode(int ind) => (IXamlIlAstValueNode)ni.Children[ind];

            var contentProperty = context.Configuration.FindContentProperty(type);

            if (contentProperty == null)
            {
                foreach (var ind in valueIndexes)
                {
                    if (XamlIlTransformHelpers.TryCallAdd(context, null, type, VNode(ind), out var addCall))
                    {
                        ni.Children[ind] = addCall;
                    }
                    else
                    {
                        throw new XamlIlLoadException(
                                  $"Type `{type.GetFqn()} does not have content property and suitable Add({VNode(ind).Type.GetClrType().GetFqn()}) not found",
                                  VNode(ind));
                    }
                }
            }
            else
            {
                XamlIlTransformHelpers.GeneratePropertyAssignments(context, contentProperty, valueIndexes.Count,
                                                                   num => VNode(valueIndexes[num]),
                                                                   (i, v) => ni.Children[valueIndexes[i]] = v);
            }
        }
Exemplo n.º 8
0
        IXamlIlConstructor TransformArgumentsAndGetConstructor(XamlIlAstTransformationContext context,
                                                               XamlIlAstObjectNode 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 XamlIlLoadException(
                              $"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 (!XamlIlTransformHelpers.TryGetCorrectlyTypedValue(context, n.Arguments[c], ctor.Parameters[c], out var arg))
                {
                    throw new XamlIlLoadException(
                              $"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);
        }
        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));
        }
        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
        {
            if (node is XamlIlAstXamlPropertyValueNode valueNode)
            {
                var property    = valueNode.Property.GetClrProperty();
                var assignments = new List <XamlIlPropertyAssignmentNode>();
                foreach (var v in valueNode.Values)
                {
                    var keyNode   = FindAndRemoveKey(v);
                    var arguments = new List <IXamlIlAstValueNode>();

                    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++)
                        {
                            IXamlIlType convertedTo = null;
                            for (var s = 0; s < filteredSetters.Count;)
                            {
                                var setter = filteredSetters[s];
                                if (convertedTo == null)
                                {
                                    if (!XamlIlTransformHelpers.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 XamlIlLoadException(
                                                  $"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++;
                            }
                        }
                    }

                    XamlIlPropertyAssignmentNode CreateAssignment()
                    {
                        var matchedSetters = new List <IXamlIlPropertySetter>();

                        foreach (var setter in filteredSetters)
                        {
                            bool CanAssign(IXamlIlAstValueNode value, IXamlIlType type)
                            {
                                // Don't allow x:Null
                                if (!setter.BinderParameters.AllowXNull &&
                                    XamlIlPseudoType.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 (XamlIlTransformHelpers.TryConvertValue(context, valueArg, setterType, property,
                                                                            out var converted))
                            {
                                arguments[valueArgIndex] = converted;
                                return(new XamlIlPropertyAssignmentNode(valueNode,
                                                                        property, new[] { setter }, arguments));
                            }
                        }

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

                        throw new XamlIlLoadException(
                                  $"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 XamlIlLoadException(
                                      $"Unable to find a setter that allows multiple assignments to the property {ass.Property.Name} of type {ass.Property.DeclaringType.GetFqn()}",
                                      node);
                        }
                    }
                }

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

            return(node);
        }
        public IXamlIlAstNode Transform(XamlIlAstTransformationContext context, IXamlIlAstNode node)
        {
            if (!(node is XamlIlAstObjectNode on &&
                  on.Type.GetClrType().FullName == "Avalonia.Styling.Setter"))
            {
                return(node);
            }

            var parent = context.ParentNodes().OfType <XamlIlAstObjectNode>()
                         .FirstOrDefault(p => p.Type.GetClrType().FullName == "Avalonia.Styling.Style");

            if (parent == null)
            {
                throw new XamlIlParseException(
                          "Avalonia.Styling.Setter is only valid inside Avalonia.Styling.Style", node);
            }
            var selectorProperty = parent.Children.OfType <XamlIlAstXamlPropertyValueNode>()
                                   .FirstOrDefault(p => p.Property.GetClrProperty().Name == "Selector");

            if (selectorProperty == null)
            {
                throw new XamlIlParseException(
                          "Can not find parent Style Selector", node);
            }
            var selector = selectorProperty.Values.FirstOrDefault() as XamlIlSelectorNode;

            if (selector?.TargetType == null)
            {
                throw new XamlIlParseException(
                          "Can not resolve parent Style Selector type", node);
            }


            var property = @on.Children.OfType <XamlIlAstXamlPropertyValueNode>()
                           .FirstOrDefault(x => x.Property.GetClrProperty().Name == "Property");

            if (property == null)
            {
                throw new XamlIlParseException("Setter without a property is not valid", node);
            }

            var propertyName = property.Values.OfType <XamlIlAstTextNode>().FirstOrDefault()?.Text;

            if (propertyName == null)
            {
                throw new XamlIlParseException("Setter.Property must be a string", node);
            }


            var avaloniaPropertyNode = XamlIlAvaloniaPropertyHelper.CreateNode(context, propertyName,
                                                                               new XamlIlAstClrTypeReference(selector, selector.TargetType, false), property.Values[0]);

            property.Values = new List <IXamlIlAstValueNode>
            {
                avaloniaPropertyNode
            };

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

            if (valueProperty?.Values?.Count == 1 && valueProperty.Values[0] is XamlIlAstTextNode)
            {
                var propType = avaloniaPropertyNode.AvaloniaPropertyType;
                if (!XamlIlTransformHelpers.TryGetCorrectlyTypedValue(context, valueProperty.Values[0],
                                                                      propType, out var converted))
                {
                    throw new XamlIlParseException(
                              $"Unable to convert property value to {propType.GetFqn()}",
                              valueProperty.Values[0]);
                }

                valueProperty.Property = new SetterValueProperty(valueProperty.Property,
                                                                 on.Type.GetClrType(), propType, context.GetAvaloniaTypes());
            }

            return(node);
        }