예제 #1
0
        public static bool CustomValueConverter(XamlIlAstTransformationContext context,
                                                IXamlIlAstValueNode node, IXamlIlType type, out IXamlIlAstValueNode result)
        {
            if (type.FullName == "System.TimeSpan" &&
                node is XamlIlAstTextNode tn &&
                !tn.Text.Contains(":"))
            {
                var seconds = double.Parse(tn.Text, CultureInfo.InvariantCulture);
                result = new XamlIlStaticOrTargetedReturnMethodCallNode(tn,
                                                                        type.FindMethod("FromSeconds", type, false, context.Configuration.WellKnownTypes.Double),
                                                                        new[]
                {
                    new XamlIlConstantNode(tn, context.Configuration.WellKnownTypes.Double, seconds)
                });
                return(true);
            }

            if (type.FullName == "Avalonia.AvaloniaProperty")
            {
                var scope = context.ParentNodes().OfType <AvaloniaXamlIlTargetTypeMetadataNode>().FirstOrDefault();
                if (scope == null)
                {
                    throw new XamlIlLoadException("Unable to find the parent scope for AvaloniaProperty lookup", node);
                }
                if (!(node is XamlIlAstTextNode text))
                {
                    throw new XamlIlLoadException("Property should be a text node", node);
                }
                result = XamlIlAvaloniaPropertyHelper.CreateNode(context, text.Text, scope.TargetType, text);
                return(true);
            }

            result = null;
            return(false);
        }
        public static bool CustomValueConverter(AstTransformationContext context,
                                                IXamlAstValueNode node, IXamlType type, out IXamlAstValueNode result)
        {
            if (!(node is XamlAstTextNode textNode))
            {
                result = null;
                return(false);
            }

            var text  = textNode.Text;
            var types = context.GetAvaloniaTypes();

            if (AvaloniaXamlIlLanguageParseIntrinsics.TryConvert(context, node, text, type, types, out result))
            {
                return(true);
            }

            if (type.FullName == "Avalonia.AvaloniaProperty")
            {
                var scope = context.ParentNodes().OfType <AvaloniaXamlIlTargetTypeMetadataNode>().FirstOrDefault();
                if (scope == null)
                {
                    throw new XamlX.XamlLoadException("Unable to find the parent scope for AvaloniaProperty lookup", node);
                }

                result = XamlIlAvaloniaPropertyHelper.CreateNode(context, text, scope.TargetType, node);
                return(true);
            }

            result = null;
            return(false);
        }
예제 #3
0
 public XamlIlAvaloniaPropertyFieldNode(AvaloniaXamlIlWellKnownTypes types,
                                        IXamlLineInfo lineInfo, IXamlField field) : base(lineInfo)
 {
     _field = field;
     AvaloniaPropertyType = XamlIlAvaloniaPropertyHelper.GetAvaloniaPropertyType(field,
                                                                                 types, lineInfo);
 }
예제 #4
0
        public static bool CustomValueConverter(AstTransformationContext context,
                                                IXamlAstValueNode node, IXamlType type, out IXamlAstValueNode result)
        {
            if (!(node is XamlAstTextNode textNode))
            {
                result = null;
                return(false);
            }

            var text = textNode.Text;

            var types = context.GetAvaloniaTypes();

            if (type.FullName == "System.TimeSpan")
            {
                var tsText = text.Trim();

                if (!TimeSpan.TryParse(tsText, CultureInfo.InvariantCulture, out var timeSpan))
                {
                    // // shorthand seconds format (ie. "0.25")
                    if (!tsText.Contains(":") && double.TryParse(tsText,
                                                                 NumberStyles.Float | NumberStyles.AllowThousands,
                                                                 CultureInfo.InvariantCulture, out var seconds))
                    {
                        timeSpan = TimeSpan.FromSeconds(seconds);
                    }
                    else
                    {
                        throw new XamlX.XamlLoadException($"Unable to parse {text} as a time span", node);
                    }
                }


                result = new XamlStaticOrTargetedReturnMethodCallNode(node,
                                                                      type.FindMethod("FromTicks", type, false, types.Long),
                                                                      new[] { new XamlConstantNode(node, types.Long, timeSpan.Ticks) });
                return(true);
            }

            if (type.Equals(types.FontFamily))
            {
                result = new AvaloniaXamlIlFontFamilyAstNode(types, text, node);
                return(true);
            }

            if (type.FullName == "Avalonia.AvaloniaProperty")
            {
                var scope = context.ParentNodes().OfType <AvaloniaXamlIlTargetTypeMetadataNode>().FirstOrDefault();
                if (scope == null)
                {
                    throw new XamlX.XamlLoadException("Unable to find the parent scope for AvaloniaProperty lookup", node);
                }

                result = XamlIlAvaloniaPropertyHelper.CreateNode(context, text, scope.TargetType, node);
                return(true);
            }

            result = null;
            return(false);
        }
예제 #5
0
 public XamlIlNodeEmitResult Emit(XamlIlEmitContext context, IXamlIlEmitter codeGen)
 {
     if (!XamlIlAvaloniaPropertyHelper.Emit(context, codeGen, Property))
     {
         throw new XamlIlLoadException(Property.Name + " is not an AvaloniaProperty", this);
     }
     return(XamlIlNodeEmitResult.Type(0, Type.GetClrType()));
 }
예제 #6
0
        public static bool CustomValueConverter(AstTransformationContext context,
                                                IXamlAstValueNode node, IXamlType type, out IXamlAstValueNode result)
        {
            if (!(node is XamlAstTextNode textNode))
            {
                result = null;
                return(false);
            }

            var text = textNode.Text;

            var types = context.GetAvaloniaTypes();

            if (type.FullName == "System.TimeSpan")
            {
                var tsText = text.Trim();

                if (!TimeSpan.TryParse(tsText, CultureInfo.InvariantCulture, out var timeSpan))
                {
                    // // shorthand seconds format (ie. "0.25")
                    if (!tsText.Contains(":") && double.TryParse(tsText,
                                                                 NumberStyles.Float | NumberStyles.AllowThousands,
                                                                 CultureInfo.InvariantCulture, out var seconds))
                    {
                        timeSpan = TimeSpan.FromSeconds(seconds);
                    }
                    else
                    {
                        throw new XamlX.XamlLoadException($"Unable to parse {text} as a time span", node);
                    }
                }


                result = new XamlStaticOrTargetedReturnMethodCallNode(node,
                                                                      type.FindMethod("FromTicks", type, false, types.Long),
                                                                      new[] { new XamlConstantNode(node, types.Long, timeSpan.Ticks) });
                return(true);
            }

            if (type.Equals(types.FontFamily))
            {
                result = new AvaloniaXamlIlFontFamilyAstNode(types, text, node);
                return(true);
            }

            if (type.Equals(types.Thickness))
            {
                var thickness = Thickness.Parse(text);

                result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.Thickness, types.ThicknessFullConstructor,
                                                                     new[] { thickness.Left, thickness.Top, thickness.Right, thickness.Bottom });

                return(true);
            }

            if (type.Equals(types.Point))
            {
                var point = Point.Parse(text);

                result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.Point, types.PointFullConstructor,
                                                                     new[] { point.X, point.Y });

                return(true);
            }

            if (type.Equals(types.Vector))
            {
                var vector = Vector.Parse(text);

                result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.Vector, types.VectorFullConstructor,
                                                                     new[] { vector.X, vector.Y });

                return(true);
            }

            if (type.Equals(types.Size))
            {
                var size = Size.Parse(text);

                result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.Size, types.SizeFullConstructor,
                                                                     new[] { size.Width, size.Height });

                return(true);
            }

            if (type.Equals(types.Matrix))
            {
                var matrix = Matrix.Parse(text);

                result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.Matrix, types.MatrixFullConstructor,
                                                                     new[] { matrix.M11, matrix.M12, matrix.M21, matrix.M22, matrix.M31, matrix.M32 });

                return(true);
            }

            if (type.Equals(types.CornerRadius))
            {
                var cornerRadius = CornerRadius.Parse(text);

                result = new AvaloniaXamlIlVectorLikeConstantAstNode(node, types, types.CornerRadius, types.CornerRadiusFullConstructor,
                                                                     new[] { cornerRadius.TopLeft, cornerRadius.TopRight, cornerRadius.BottomRight, cornerRadius.BottomLeft });

                return(true);
            }

            if (type.FullName == "Avalonia.AvaloniaProperty")
            {
                var scope = context.ParentNodes().OfType <AvaloniaXamlIlTargetTypeMetadataNode>().FirstOrDefault();
                if (scope == null)
                {
                    throw new XamlX.XamlLoadException("Unable to find the parent scope for AvaloniaProperty lookup", node);
                }

                result = XamlIlAvaloniaPropertyHelper.CreateNode(context, text, scope.TargetType, node);
                return(true);
            }

            result = null;
            return(false);
        }
        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;