Browse Source
Conflicts: src/Markup/Perspex.Markup.Xaml/Context/PerspexWiringContext.cs src/Markup/Perspex.Markup.Xaml/Properties/AssemblyInfo.cspull/145/head
32 changed files with 1072 additions and 96 deletions
@ -0,0 +1,63 @@ |
|||||
|
// Copyright (c) The Perspex Project. All rights reserved.
|
||||
|
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
||||
|
|
||||
|
using Moq; |
||||
|
using OmniXaml; |
||||
|
using OmniXaml.TypeConversion; |
||||
|
using OmniXaml.Typing; |
||||
|
using Perspex.Markup.Xaml.Converters; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Perspex.Markup.Xaml.UnitTests.Converters |
||||
|
{ |
||||
|
public class PerspexPropertyConverterTest |
||||
|
{ |
||||
|
public PerspexPropertyConverterTest() |
||||
|
{ |
||||
|
// Ensure properties are registered.
|
||||
|
var foo = Class1.FooProperty; |
||||
|
var attached = AttachedOwner.AttachedProperty; |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void ConvertFrom_Finds_Fully_Qualified_Property() |
||||
|
{ |
||||
|
var target = new PerspexPropertyConverter(); |
||||
|
var context = CreateContext(); |
||||
|
var result = target.ConvertFrom(context, null, "Class1.Foo"); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void ConvertFrom_Finds_Attached_Property() |
||||
|
{ |
||||
|
var target = new PerspexPropertyConverter(); |
||||
|
var context = CreateContext(); |
||||
|
var result = target.ConvertFrom(context, null, "AttachedOwner.Attached"); |
||||
|
} |
||||
|
|
||||
|
private IXamlTypeConverterContext CreateContext() |
||||
|
{ |
||||
|
var context = new Mock<IXamlTypeConverterContext>(); |
||||
|
var typeRepository = new Mock<IXamlTypeRepository>(); |
||||
|
var featureProvider = new Mock<ITypeFeatureProvider>(); |
||||
|
var class1XamlType = new XamlType(typeof(Class1), typeRepository.Object, null, featureProvider.Object); |
||||
|
var attachedOwnerXamlType = new XamlType(typeof(AttachedOwner), typeRepository.Object, null, featureProvider.Object); |
||||
|
context.Setup(x => x.TypeRepository).Returns(typeRepository.Object); |
||||
|
typeRepository.Setup(x => x.GetByQualifiedName("Class1")).Returns(class1XamlType); |
||||
|
typeRepository.Setup(x => x.GetByQualifiedName("AttachedOwner")).Returns(attachedOwnerXamlType); |
||||
|
return context.Object; |
||||
|
} |
||||
|
|
||||
|
private class Class1 : PerspexObject |
||||
|
{ |
||||
|
public static readonly PerspexProperty<string> FooProperty = |
||||
|
PerspexProperty.Register<Class1, string>("Foo"); |
||||
|
} |
||||
|
|
||||
|
private class AttachedOwner |
||||
|
{ |
||||
|
public static readonly PerspexProperty<string> AttachedProperty = |
||||
|
PerspexProperty.RegisterAttached<AttachedOwner, Class1, string>("Attached"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,189 @@ |
|||||
|
// Copyright (c) The Perspex Project. All rights reserved.
|
||||
|
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
||||
|
|
||||
|
using System.Linq; |
||||
|
using Perspex.Markup.Xaml.Parsers; |
||||
|
using Sprache; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Perspex.Xaml.Base.UnitTest.Parsers |
||||
|
{ |
||||
|
public class SelectorGrammarTests |
||||
|
{ |
||||
|
[Fact] |
||||
|
public void OfType() |
||||
|
{ |
||||
|
var result = SelectorGrammar.Selector.Parse("Button").ToList(); |
||||
|
|
||||
|
Assert.Equal( |
||||
|
new[] { new SelectorGrammar.OfTypeSyntax { TypeName = "Button", Xmlns = null } }, |
||||
|
result); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void NamespacedOfType() |
||||
|
{ |
||||
|
var result = SelectorGrammar.Selector.Parse("x|Button").ToList(); |
||||
|
|
||||
|
Assert.Equal( |
||||
|
new[] { new SelectorGrammar.OfTypeSyntax { TypeName = "Button", Xmlns = "x" } }, |
||||
|
result); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Name() |
||||
|
{ |
||||
|
var result = SelectorGrammar.Selector.Parse("#foo").ToList(); |
||||
|
|
||||
|
Assert.Equal( |
||||
|
new[] { new SelectorGrammar.NameSyntax { Name = "foo" }, }, |
||||
|
result); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void OfType_Name() |
||||
|
{ |
||||
|
var result = SelectorGrammar.Selector.Parse("Button#foo").ToList(); |
||||
|
|
||||
|
Assert.Equal( |
||||
|
new SelectorGrammar.ISyntax[] |
||||
|
{ |
||||
|
new SelectorGrammar.OfTypeSyntax { TypeName = "Button" }, |
||||
|
new SelectorGrammar.NameSyntax { Name = "foo" }, |
||||
|
}, |
||||
|
result); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Class() |
||||
|
{ |
||||
|
var result = SelectorGrammar.Selector.Parse(".foo").ToList(); |
||||
|
|
||||
|
Assert.Equal( |
||||
|
new[] { new SelectorGrammar.ClassSyntax { Class = "foo" } }, |
||||
|
result); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Pseudoclass() |
||||
|
{ |
||||
|
var result = SelectorGrammar.Selector.Parse(":foo").ToList(); |
||||
|
|
||||
|
Assert.Equal( |
||||
|
new[] { new SelectorGrammar.ClassSyntax { Class = ":foo" } }, |
||||
|
result); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void OfType_Class() |
||||
|
{ |
||||
|
var result = SelectorGrammar.Selector.Parse("Button.foo").ToList(); |
||||
|
|
||||
|
Assert.Equal( |
||||
|
new SelectorGrammar.ISyntax[] |
||||
|
{ |
||||
|
new SelectorGrammar.OfTypeSyntax { TypeName = "Button" }, |
||||
|
new SelectorGrammar.ClassSyntax { Class = "foo" }, |
||||
|
}, |
||||
|
result); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void OfType_Child_Class() |
||||
|
{ |
||||
|
var result = SelectorGrammar.Selector.Parse("Button < .foo").ToList(); |
||||
|
|
||||
|
Assert.Equal( |
||||
|
new SelectorGrammar.ISyntax[] |
||||
|
{ |
||||
|
new SelectorGrammar.OfTypeSyntax { TypeName = "Button" }, |
||||
|
new SelectorGrammar.ChildSyntax { }, |
||||
|
new SelectorGrammar.ClassSyntax { Class = "foo" }, |
||||
|
}, |
||||
|
result); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void OfType_Child_Class_No_Spaces() |
||||
|
{ |
||||
|
var result = SelectorGrammar.Selector.Parse("Button<.foo").ToList(); |
||||
|
|
||||
|
Assert.Equal( |
||||
|
new SelectorGrammar.ISyntax[] |
||||
|
{ |
||||
|
new SelectorGrammar.OfTypeSyntax { TypeName = "Button" }, |
||||
|
new SelectorGrammar.ChildSyntax { }, |
||||
|
new SelectorGrammar.ClassSyntax { Class = "foo" }, |
||||
|
}, |
||||
|
result); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void OfType_Descendent_Class() |
||||
|
{ |
||||
|
var result = SelectorGrammar.Selector.Parse("Button .foo").ToList(); |
||||
|
|
||||
|
Assert.Equal( |
||||
|
new SelectorGrammar.ISyntax[] |
||||
|
{ |
||||
|
new SelectorGrammar.OfTypeSyntax { TypeName = "Button" }, |
||||
|
new SelectorGrammar.DescendentSyntax { }, |
||||
|
new SelectorGrammar.ClassSyntax { Class = "foo" }, |
||||
|
}, |
||||
|
result); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void OfType_Template_Class() |
||||
|
{ |
||||
|
var result = SelectorGrammar.Selector.Parse("Button /template/ .foo").ToList(); |
||||
|
|
||||
|
Assert.Equal( |
||||
|
new SelectorGrammar.ISyntax[] |
||||
|
{ |
||||
|
new SelectorGrammar.OfTypeSyntax { TypeName = "Button" }, |
||||
|
new SelectorGrammar.TemplateSyntax { }, |
||||
|
new SelectorGrammar.ClassSyntax { Class = "foo" }, |
||||
|
}, |
||||
|
result); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void OfType_Property() |
||||
|
{ |
||||
|
var result = SelectorGrammar.Selector.Parse("Button[Foo=bar]").ToList(); |
||||
|
|
||||
|
Assert.Equal( |
||||
|
new SelectorGrammar.ISyntax[] |
||||
|
{ |
||||
|
new SelectorGrammar.OfTypeSyntax { TypeName = "Button" }, |
||||
|
new SelectorGrammar.PropertySyntax { Property = "Foo", Value = "bar" }, |
||||
|
}, |
||||
|
result); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Namespace_Alone_Fails() |
||||
|
{ |
||||
|
Assert.Throws<ParseException>(() => SelectorGrammar.Selector.Parse("ns|").ToList()); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Dot_Alone_Fails() |
||||
|
{ |
||||
|
Assert.Throws<ParseException>(() => SelectorGrammar.Selector.Parse(". dot").ToList()); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Invalid_Identifier_Fails() |
||||
|
{ |
||||
|
Assert.Throws<ParseException>(() => SelectorGrammar.Selector.Parse("%foo").ToList()); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Invalid_Class_Fails() |
||||
|
{ |
||||
|
Assert.Throws<ParseException>(() => SelectorGrammar.Selector.Parse(".%foo").ToList()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,33 @@ |
|||||
|
// Copyright (c) The Perspex Project. All rights reserved.
|
||||
|
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
||||
|
|
||||
|
using System; |
||||
|
using System.Globalization; |
||||
|
using OmniXaml.TypeConversion; |
||||
|
using Perspex.Styling; |
||||
|
|
||||
|
namespace Perspex.Markup.Xaml.Converters |
||||
|
{ |
||||
|
public class ClassesConverter : ITypeConverter |
||||
|
{ |
||||
|
public bool CanConvertFrom(IXamlTypeConverterContext context, Type sourceType) |
||||
|
{ |
||||
|
return sourceType == typeof(string); |
||||
|
} |
||||
|
|
||||
|
public bool CanConvertTo(IXamlTypeConverterContext context, Type destinationType) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
public object ConvertFrom(IXamlTypeConverterContext context, CultureInfo culture, object value) |
||||
|
{ |
||||
|
return new Classes(((string)value).Split(' ')); |
||||
|
} |
||||
|
|
||||
|
public object ConvertTo(IXamlTypeConverterContext context, CultureInfo culture, object value, Type destinationType) |
||||
|
{ |
||||
|
throw new NotImplementedException(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,72 @@ |
|||||
|
// Copyright (c) The Perspex Project. All rights reserved.
|
||||
|
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
||||
|
|
||||
|
using System; |
||||
|
using System.Globalization; |
||||
|
using System.Linq; |
||||
|
using OmniXaml; |
||||
|
using OmniXaml.TypeConversion; |
||||
|
using Perspex.Styling; |
||||
|
|
||||
|
namespace Perspex.Markup.Xaml.Converters |
||||
|
{ |
||||
|
public class PerspexPropertyConverter : ITypeConverter |
||||
|
{ |
||||
|
public bool CanConvertFrom(IXamlTypeConverterContext context, Type sourceType) |
||||
|
{ |
||||
|
return sourceType == typeof(string); |
||||
|
} |
||||
|
|
||||
|
public bool CanConvertTo(IXamlTypeConverterContext context, Type destinationType) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
public object ConvertFrom(IXamlTypeConverterContext context, CultureInfo culture, object value) |
||||
|
{ |
||||
|
var s = (string)value; |
||||
|
var lastDot = s.LastIndexOf('.'); |
||||
|
|
||||
|
if (lastDot == -1) |
||||
|
{ |
||||
|
throw new NotSupportedException("PerspexProperties must currently be fully qualified."); |
||||
|
} |
||||
|
|
||||
|
var typeName = s.Substring(0, lastDot); |
||||
|
var propertyName = s.Substring(lastDot + 1); |
||||
|
var type = context.TypeRepository.GetByQualifiedName(typeName)?.UnderlyingType; |
||||
|
var styleType = context.TypeRepository.GetXamlType(typeof(Style)); |
||||
|
|
||||
|
// ATTN: SuperJMN
|
||||
|
//var style = ((XamlTypeConverterContext)context).TopDownValueContext.GetLastInstance(styleType);
|
||||
|
|
||||
|
if (type == null) |
||||
|
{ |
||||
|
throw new XamlParseException($"Could not find type '{typeName}'."); |
||||
|
} |
||||
|
|
||||
|
// First look for non-attached property on the type and then look for an attached property.
|
||||
|
var property = PerspexObject.GetRegisteredProperties(type) |
||||
|
.FirstOrDefault(x => x.Name == propertyName && !x.IsAttached); |
||||
|
|
||||
|
if (property == null) |
||||
|
{ |
||||
|
property = PerspexObject.GetAttachedProperties(type) |
||||
|
.FirstOrDefault(x => x.Name == propertyName); |
||||
|
} |
||||
|
|
||||
|
if (property == null) |
||||
|
{ |
||||
|
throw new XamlParseException( |
||||
|
$"Could not find PerspexProperty '{typeName}'.{propertyName}."); |
||||
|
} |
||||
|
|
||||
|
return property; |
||||
|
} |
||||
|
|
||||
|
public object ConvertTo(IXamlTypeConverterContext context, CultureInfo culture, object value, Type destinationType) |
||||
|
{ |
||||
|
throw new NotImplementedException(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,34 @@ |
|||||
|
// Copyright (c) The Perspex Project. All rights reserved.
|
||||
|
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
||||
|
|
||||
|
using System; |
||||
|
using System.Globalization; |
||||
|
using OmniXaml.TypeConversion; |
||||
|
using Perspex.Markup.Xaml.Parsers; |
||||
|
|
||||
|
namespace Perspex.Markup.Xaml.Converters |
||||
|
{ |
||||
|
public class SelectorConverter : ITypeConverter |
||||
|
{ |
||||
|
public bool CanConvertFrom(IXamlTypeConverterContext context, Type sourceType) |
||||
|
{ |
||||
|
return sourceType == typeof(string); |
||||
|
} |
||||
|
|
||||
|
public bool CanConvertTo(IXamlTypeConverterContext context, Type destinationType) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
public object ConvertFrom(IXamlTypeConverterContext context, CultureInfo culture, object value) |
||||
|
{ |
||||
|
var parser = new SelectorParser((t, ns) => context.TypeRepository.GetByPrefix(ns ?? "", t).UnderlyingType); |
||||
|
return parser.Parse((string)value); |
||||
|
} |
||||
|
|
||||
|
public object ConvertTo(IXamlTypeConverterContext context, CultureInfo culture, object value, Type destinationType) |
||||
|
{ |
||||
|
throw new NotImplementedException(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1 @@ |
|||||
|
Subproject commit 59318a343cdb3e94e5ee33a05b5ffac2771e9640 |
||||
@ -0,0 +1,187 @@ |
|||||
|
// Copyright (c) The Perspex Project. All rights reserved.
|
||||
|
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
||||
|
|
||||
|
using System.Collections.Generic; |
||||
|
using System.Globalization; |
||||
|
using System.Linq; |
||||
|
using Perspex.Styling; |
||||
|
using Sprache; |
||||
|
|
||||
|
namespace Perspex.Markup.Xaml.Parsers |
||||
|
{ |
||||
|
internal class SelectorGrammar |
||||
|
{ |
||||
|
public static readonly Parser<char> CombiningCharacter = Parse.Char( |
||||
|
c => |
||||
|
{ |
||||
|
var cat = CharUnicodeInfo.GetUnicodeCategory(c); |
||||
|
return cat == UnicodeCategory.NonSpacingMark || |
||||
|
cat == UnicodeCategory.SpacingCombiningMark; |
||||
|
}, |
||||
|
"Connecting Character"); |
||||
|
|
||||
|
public static readonly Parser<char> ConnectingCharacter = Parse.Char( |
||||
|
c => CharUnicodeInfo.GetUnicodeCategory(c) == UnicodeCategory.ConnectorPunctuation, |
||||
|
"Connecting Character"); |
||||
|
|
||||
|
public static readonly Parser<char> FormattingCharacter = Parse.Char( |
||||
|
c => CharUnicodeInfo.GetUnicodeCategory(c) == UnicodeCategory.Format, |
||||
|
"Connecting Character"); |
||||
|
|
||||
|
public static readonly Parser<char> IdentifierStart = Parse.Letter.Or(Parse.Char('_')); |
||||
|
|
||||
|
public static readonly Parser<char> IdentifierChar = Parse |
||||
|
.LetterOrDigit |
||||
|
.Or(ConnectingCharacter) |
||||
|
.Or(CombiningCharacter) |
||||
|
.Or(FormattingCharacter); |
||||
|
|
||||
|
public static readonly Parser<string> Identifier = |
||||
|
from start in IdentifierStart.Once().Text() |
||||
|
from @char in IdentifierChar.Many().Text() |
||||
|
select start + @char; |
||||
|
|
||||
|
public static readonly Parser<string> Namespace = |
||||
|
from ns in Parse.Letter.Many().Text() |
||||
|
from bar in Parse.Char('|') |
||||
|
select ns; |
||||
|
|
||||
|
public static readonly Parser<OfTypeSyntax> OfType = |
||||
|
from ns in Namespace.Optional() |
||||
|
from identifier in Identifier |
||||
|
select new OfTypeSyntax |
||||
|
{ |
||||
|
TypeName = identifier, |
||||
|
Xmlns = ns.GetOrDefault(), |
||||
|
}; |
||||
|
|
||||
|
public static readonly Parser<NameSyntax> Name = |
||||
|
from hash in Parse.Char('#') |
||||
|
from identifier in Identifier |
||||
|
select new NameSyntax { Name = identifier }; |
||||
|
|
||||
|
public static readonly Parser<char> ClassStart = Parse.Char('_').Or(Parse.Letter); |
||||
|
|
||||
|
public static readonly Parser<char> ClassChar = ClassStart.Or(Parse.Numeric); |
||||
|
|
||||
|
public static readonly Parser<string> ClassIdentifier = |
||||
|
from start in ClassStart.Once().Text() |
||||
|
from @char in ClassChar.Many().Text() |
||||
|
select start + @char; |
||||
|
|
||||
|
public static readonly Parser<ClassSyntax> StandardClass = |
||||
|
from dot in Parse.Char('.').Once() |
||||
|
from identifier in ClassIdentifier |
||||
|
select new ClassSyntax { Class = identifier }; |
||||
|
|
||||
|
public static readonly Parser<ClassSyntax> Pseduoclass = |
||||
|
from colon in Parse.Char(':').Once() |
||||
|
from identifier in ClassIdentifier |
||||
|
select new ClassSyntax { Class = ':' + identifier }; |
||||
|
|
||||
|
public static readonly Parser<ClassSyntax> Class = StandardClass.Or(Pseduoclass); |
||||
|
|
||||
|
public static readonly Parser<PropertySyntax> Property = |
||||
|
from open in Parse.Char('[').Once() |
||||
|
from identifier in Identifier |
||||
|
from eq in Parse.Char('=').Once() |
||||
|
from value in Parse.CharExcept(']').Many().Text() |
||||
|
from close in Parse.Char(']').Once() |
||||
|
select new PropertySyntax { Property = identifier, Value = value }; |
||||
|
|
||||
|
public static readonly Parser<ChildSyntax> Child = Parse.Char('<').Token().Return(new ChildSyntax()); |
||||
|
|
||||
|
public static readonly Parser<DescendentSyntax> Descendent = |
||||
|
from child in Parse.WhiteSpace.Many() |
||||
|
select new DescendentSyntax(); |
||||
|
|
||||
|
public static readonly Parser<TemplateSyntax> Template = |
||||
|
from template in Parse.String("/template/").Token() |
||||
|
select new TemplateSyntax(); |
||||
|
|
||||
|
public static readonly Parser<ISyntax> SingleSelector = |
||||
|
OfType |
||||
|
.Or<ISyntax>(Name) |
||||
|
.Or<ISyntax>(Class) |
||||
|
.Or<ISyntax>(Property) |
||||
|
.Or<ISyntax>(Child) |
||||
|
.Or<ISyntax>(Template) |
||||
|
.Or<ISyntax>(Descendent); |
||||
|
|
||||
|
public static readonly Parser<IEnumerable<ISyntax>> Selector = SingleSelector.Many().End(); |
||||
|
|
||||
|
public interface ISyntax |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public class OfTypeSyntax : ISyntax |
||||
|
{ |
||||
|
public string TypeName { get; set; } |
||||
|
|
||||
|
public string Xmlns { get; set; } |
||||
|
|
||||
|
public override bool Equals(object obj) |
||||
|
{ |
||||
|
return obj is OfTypeSyntax && ((OfTypeSyntax)obj).TypeName == TypeName; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public class ClassSyntax : ISyntax |
||||
|
{ |
||||
|
public string Class { get; set; } |
||||
|
|
||||
|
public override bool Equals(object obj) |
||||
|
{ |
||||
|
return obj is ClassSyntax && ((ClassSyntax)obj).Class == Class; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public class NameSyntax : ISyntax |
||||
|
{ |
||||
|
public string Name { get; set; } |
||||
|
|
||||
|
public override bool Equals(object obj) |
||||
|
{ |
||||
|
return obj is NameSyntax && ((NameSyntax)obj).Name == Name; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public class PropertySyntax : ISyntax |
||||
|
{ |
||||
|
public string Property { get; set; } |
||||
|
|
||||
|
public string Value { get; set; } |
||||
|
|
||||
|
public override bool Equals(object obj) |
||||
|
{ |
||||
|
return obj is PropertySyntax && |
||||
|
((PropertySyntax)obj).Property == Property && |
||||
|
((PropertySyntax)obj).Value == Value; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public class ChildSyntax : ISyntax |
||||
|
{ |
||||
|
public override bool Equals(object obj) |
||||
|
{ |
||||
|
return obj is ChildSyntax; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public class DescendentSyntax : ISyntax |
||||
|
{ |
||||
|
public override bool Equals(object obj) |
||||
|
{ |
||||
|
return obj is DescendentSyntax; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public class TemplateSyntax : ISyntax |
||||
|
{ |
||||
|
public override bool Equals(object obj) |
||||
|
{ |
||||
|
return obj is TemplateSyntax; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,83 @@ |
|||||
|
// Copyright (c) The Perspex Project. All rights reserved.
|
||||
|
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
||||
|
|
||||
|
using System; |
||||
|
using Perspex.Styling; |
||||
|
using Sprache; |
||||
|
|
||||
|
namespace Perspex.Markup.Xaml.Parsers |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Parses a <see cref="Selector"/> from text.
|
||||
|
/// </summary>
|
||||
|
public class SelectorParser |
||||
|
{ |
||||
|
private Func<string, string, Type> _typeResolver; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="SelectorParser"/> class.
|
||||
|
/// </summary>
|
||||
|
/// <param name="typeResolver">
|
||||
|
/// The type resolver to use. The type resolver is a function which accepts two strings:
|
||||
|
/// a type name and a XML namespace prefix and a type name, and should return the resolved
|
||||
|
/// type or throw an exception.
|
||||
|
/// </param>
|
||||
|
public SelectorParser(Func<string, string, Type> typeResolver) |
||||
|
{ |
||||
|
this._typeResolver = typeResolver; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Parses a <see cref="Selector"/> from a string.
|
||||
|
/// </summary>
|
||||
|
/// <param name="s">The string.</param>
|
||||
|
/// <returns>The parsed selector.</returns>
|
||||
|
public Selector Parse(string s) |
||||
|
{ |
||||
|
var syntax = SelectorGrammar.Selector.Parse(s); |
||||
|
var result = new Selector(); |
||||
|
|
||||
|
foreach (var i in syntax) |
||||
|
{ |
||||
|
var ofType = i as SelectorGrammar.OfTypeSyntax; |
||||
|
var @class = i as SelectorGrammar.ClassSyntax; |
||||
|
var name = i as SelectorGrammar.NameSyntax; |
||||
|
var property = i as SelectorGrammar.PropertySyntax; |
||||
|
var child = i as SelectorGrammar.ChildSyntax; |
||||
|
var descendent = i as SelectorGrammar.DescendentSyntax; |
||||
|
var template = i as SelectorGrammar.TemplateSyntax; |
||||
|
|
||||
|
if (ofType != null) |
||||
|
{ |
||||
|
result = result.OfType(_typeResolver(ofType.TypeName, ofType.Xmlns)); |
||||
|
} |
||||
|
else if (@class != null) |
||||
|
{ |
||||
|
result = result.Class(@class.Class); |
||||
|
} |
||||
|
else if (name != null) |
||||
|
{ |
||||
|
result = result.Name(name.Name); |
||||
|
} |
||||
|
else if (property != null) |
||||
|
{ |
||||
|
throw new NotImplementedException(); |
||||
|
} |
||||
|
else if (child != null) |
||||
|
{ |
||||
|
result = result.Child(); |
||||
|
} |
||||
|
else if (descendent != null) |
||||
|
{ |
||||
|
result = result.Descendent(); |
||||
|
} |
||||
|
else if (template != null) |
||||
|
{ |
||||
|
result = result.Template(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue