private static bool GetRelativeSourceObjectFromAssignment( AstTransformationContext context, XamlAstXamlPropertyValueNode relativeSourceProperty, out XamlAstObjectNode relativeSourceObject) { relativeSourceObject = null; if (relativeSourceProperty is null) { return(false); } if (relativeSourceProperty.Values[0] is XamlMarkupExtensionNode me) { if (me.Type.GetClrType() != context.GetAvaloniaTypes().RelativeSource) { throw new XamlParseException($"Expected an object of type 'Avalonia.Data.RelativeSource'. Found a object of type '{me.Type.GetClrType().GetFqn()}'", me); } relativeSourceObject = (XamlAstObjectNode)me.Value; return(true); } if (relativeSourceProperty.Values[0] is XamlAstObjectNode on) { if (on.Type.GetClrType() != context.GetAvaloniaTypes().RelativeSource) { throw new XamlParseException($"Expected an object of type 'Avalonia.Data.RelativeSource'. Found a object of type '{on.Type.GetClrType().GetFqn()}'", on); } relativeSourceObject = on; return(true); } return(false); }
public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node) { if (!(node is XamlAstXamlPropertyValueNode propertyValueNode)) { return(node); } if (!(propertyValueNode.Property is XamlAstClrProperty clrProperty)) { return(node); } IEnumerable <IXamlCustomAttribute> attributes = propertyValueNode.Property.GetClrProperty().CustomAttributes; if (propertyValueNode.Property is XamlAstClrProperty referenceNode && referenceNode.Getter != null) { attributes = attributes.Concat(referenceNode.Getter.CustomAttributes); } if (attributes.All(attribute => attribute.Type.FullName != "Avalonia.Controls.ResolveByNameAttribute")) { return(node); } if (propertyValueNode.Values.Count != 1 || !(propertyValueNode.Values.First() is XamlAstTextNode)) { return(node); } var newNode = new XamlAstObjectNode( propertyValueNode.Values[0], new XamlAstClrTypeReference(propertyValueNode.Values[0], context.GetAvaloniaTypes().ResolveByNameExtension, true)) { Arguments = new List <IXamlAstValueNode> { propertyValueNode.Values[0] } }; if (XamlTransformHelpers.TryConvertMarkupExtension(context, newNode, out var extensionNode)) { propertyValueNode.Values[0] = extensionNode; } return(node); }
IXamlConstructor TransformArgumentsAndGetConstructor( AstTransformationContext context, XamlAstObjectNode n) { var type = n.Type.GetClrType(); var argTypes = n.Arguments.Select(a => a.Type.GetClrType()).ToList(); var ctor = type.FindConstructor(argTypes); if (ctor == null) { if (argTypes.Count != 0) { ctor = type.Constructors.FirstOrDefault(x => !x.IsStatic && x.IsPublic && x.Parameters.Count == argTypes.Count); } if (ctor == null) { throw new XamlLoadException( $"Unable to find public constructor for type {type.GetFqn()}({string.Join(", ", argTypes.Select(at => at.GetFqn()))})", n); } } for (var c = 0; c < n.Arguments.Count; c++) { if (!XamlTransformHelpers.TryGetCorrectlyTypedValue(context, n.Arguments[c], ctor.Parameters[c], out var arg)) { throw new XamlLoadException( $"Unable to convert {n.Arguments[c].Type.GetClrType().GetFqn()} to {ctor.Parameters[c].GetFqn()} for constructor of {n.Type.GetClrType().GetFqn()}", n.Arguments[c]); } n.Arguments[c] = arg; } return(ctor); }
private static 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 static IXamlAstValueNode Parse(IXamlLineInfo li, string ext, Func <string, XamlAstXmlTypeReference> typeResolver) { var ctx = new MeScannerContext(typeResolver, li); var scanner = new MeScanner(ctx, ext, li.Line, li.Position); var currentTypeStack = new Stack <MeScannerTypeName>(); IXamlAstValueNode ReadExtension() { if (scanner.Token != MeTokenType.Open) { throw new MeScannerParseException("Unexpected token " + scanner.Token); } scanner.Read(); if (scanner.Token != MeTokenType.TypeName) { throw new MeScannerParseException("Unexpected token " + scanner.Token); } var extType = scanner.TokenType; extType.TypeReference.IsMarkupExtension = true; currentTypeStack.Push(ctx.CurrentType); ctx.CurrentType = extType; var rv = new XamlAstObjectNode(li, extType.TypeReference); while (true) { scanner.Read(); if (scanner.Token == MeTokenType.Close) { break; } else if (scanner.Token == MeTokenType.PropertyName) { var prop = scanner.TokenProperty; scanner.Read(); if (scanner.Token != MeTokenType.EqualSign) { throw new MeScannerParseException("Unexpected token " + scanner.Token); } var propValue = Read(); rv.Children.Add(new XamlAstXamlPropertyValueNode(li, prop, propValue)); } else if (scanner.Token == MeTokenType.String || scanner.Token == MeTokenType.QuotedMarkupExtension || scanner.Token == MeTokenType.Open) { if (rv.Children.Count != 0) { throw new MeScannerParseException("Unexpected token after property list " + scanner.Token); } rv.Arguments.Add(ReadCurrent()); } else if (scanner.Token == MeTokenType.Comma) { continue; } else { throw new MeScannerParseException("Unexpected token " + scanner.Token); } } ctx.CurrentType = currentTypeStack.Pop(); return(rv); } IXamlAstValueNode Read() { scanner.Read(); return(ReadCurrent()); } IXamlAstValueNode ReadCurrent() { if (scanner.Token == MeTokenType.String) { return(new XamlAstTextNode(li, scanner.TokenText, true)); } if (scanner.Token == MeTokenType.Open) { return(ReadExtension()); } if (scanner.Token == MeTokenType.QuotedMarkupExtension) { return(Parse(li, scanner.TokenText, typeResolver)); } throw new MeScannerParseException("Unexpected token " + scanner.Token); } return(Read()); }
XamlAstObjectNode ParseNewInstance(XElement el, bool root) { if (el.Name.LocalName.Contains(".")) { throw ParseError(el, "Dots aren't allowed in type names"); } var type = GetTypeReference(el); var i = new XamlAstObjectNode(el.AsLi(), type); foreach (var attr in el.Attributes()) { if (attr.Name.NamespaceName == "http://www.w3.org/2000/xmlns/" || (attr.Name.NamespaceName == "" && attr.Name.LocalName == "xmlns")) { if (!root) { throw ParseError(attr, "xmlns declarations are only allowed on the root element to preserve memory"); } } else if (attr.Name.NamespaceName.StartsWith("http://www.w3.org")) { // Silently ignore all xml-parser related attributes } // Parse type arguments else if (attr.Name.NamespaceName == XamlNamespaces.Xaml2006 && attr.Name.LocalName == "TypeArguments") { type.GenericArguments = ParseTypeArguments(attr.Value, el, attr.AsLi()); } // Parse as a directive else if (attr.Name.NamespaceName != "" && !attr.Name.LocalName.Contains(".")) { i.Children.Add(new XamlAstXmlDirective(el.AsLi(), attr.Name.NamespaceName, attr.Name.LocalName, new[] { ParseTextValueOrMarkupExtension(attr.Value, el, attr.AsLi()) } )); } // Parse as a property else { var pname = attr.Name.LocalName; var ptype = i.Type; if (pname.Contains(".")) { var parts = pname.Split(new[] { '.' }, 2); pname = parts[1]; var ns = attr.Name.Namespace == "" ? el.GetDefaultNamespace().NamespaceName : attr.Name.NamespaceName; ptype = new XamlAstXmlTypeReference(el.AsLi(), ns, parts[0]); } i.Children.Add(new XamlAstXamlPropertyValueNode(el.AsLi(), new XamlAstNamePropertyReference(el.AsLi(), ptype, pname, type), ParseTextValueOrMarkupExtension(attr.Value, el, attr.AsLi()))); } } foreach (var node in el.Nodes()) { if (node is XElement elementNode && elementNode.Name.LocalName.Contains(".")) { if (elementNode.HasAttributes) { throw ParseError(node, "Attributes aren't allowed on element properties"); } var pair = elementNode.Name.LocalName.Split(new[] { '.' }, 2); i.Children.Add(new XamlAstXamlPropertyValueNode(el.AsLi(), new XamlAstNamePropertyReference ( el.AsLi(), new XamlAstXmlTypeReference(el.AsLi(), elementNode.Name.NamespaceName, pair[0]), pair[1], type ), ParseValueNodeChildren(elementNode) )); }