Browse Source

Started implementing Selector parser.

pull/145/head
Steven Kirk 11 years ago
parent
commit
eb220a9388
  1. 140
      Tests/Perspex.Markup.Xaml.UnitTests/Parsers/SelectorGrammarTests.cs
  2. 9
      Tests/Perspex.Markup.Xaml.UnitTests/Perspex.Markup.Xaml.UnitTests.csproj
  3. 1
      Tests/Perspex.Markup.Xaml.UnitTests/packages.config
  4. 176
      src/Markup/Perspex.Markup.Xaml/Parsers/SelectorGrammar.cs
  5. 2
      src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj
  6. 2
      src/Markup/Perspex.Markup.Xaml/Properties/AssemblyInfo.cs
  7. 2
      src/Perspex.Styling/Styling/Selectors.cs

140
Tests/Perspex.Markup.Xaml.UnitTests/Parsers/SelectorGrammarTests.cs

@ -0,0 +1,140 @@
// 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" } },
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_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);
}
}
}

9
Tests/Perspex.Markup.Xaml.UnitTests/Perspex.Markup.Xaml.UnitTests.csproj

@ -8,8 +8,8 @@
<ProjectGuid>{99135EAB-653D-47E4-A378-C96E1278CA44}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Perspex.Xaml.Base.UnitTest</RootNamespace>
<AssemblyName>Perspex.Xaml.Base.UnitTest</AssemblyName>
<RootNamespace>Perspex.Markup.Xaml.UnitTests</RootNamespace>
<AssemblyName>Perspex.Markup.Xaml.UnitTests</AssemblyName>
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
@ -61,6 +61,10 @@
<HintPath>..\..\packages\Splat.1.6.1\lib\Net45\Splat.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Sprache, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Sprache.SuperJMN.2.0.0.50\lib\portable-net451+netcore451+wpa81\Sprache.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Reactive.Core, Version=2.2.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll</HintPath>
@ -103,6 +107,7 @@
<Compile Include="BindingDefinitionBuilder.cs" />
<Compile Include="ChangeBranchTest.cs" />
<Compile Include="DataContextChangeSynchronizerTest.cs" />
<Compile Include="Parsers\SelectorGrammarTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SampleModel\Level1.cs" />
<Compile Include="SampleModel\Level2.cs" />

1
Tests/Perspex.Markup.Xaml.UnitTests/packages.config

@ -8,6 +8,7 @@
<package id="Rx-Main" version="2.2.5" targetFramework="net451" />
<package id="Rx-PlatformServices" version="2.2.5" targetFramework="net451" />
<package id="Splat" version="1.6.1" targetFramework="net451" />
<package id="Sprache.SuperJMN" version="2.0.0.50" targetFramework="net451" />
<package id="xunit" version="2.0.0" targetFramework="net451" />
<package id="xunit.abstractions" version="2.0.0" targetFramework="net451" />
<package id="xunit.assert" version="2.0.0" targetFramework="net451" />

176
src/Markup/Perspex.Markup.Xaml/Parsers/SelectorGrammar.cs

@ -0,0 +1,176 @@
// 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<OfTypeSyntax> OfType =
from identifier in Identifier select new OfTypeSyntax { TypeName = identifier };
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
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();
public interface ISyntax
{
}
public class OfTypeSyntax : ISyntax
{
public string TypeName { 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;
}
}
}
}

2
src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj

@ -40,6 +40,7 @@
</Compile>
<Compile Include="Converters\RowDefinitionsTypeConverter.cs" />
<Compile Include="Converters\ColumnDefinitionsTypeConverter.cs" />
<Compile Include="Converters\SelectorConverter.cs" />
<Compile Include="Converters\ThicknessConverter.cs" />
<Compile Include="Context\PerspexWiringContext.cs" />
<Compile Include="MarkupExtensions\BindingExtension.cs" />
@ -51,6 +52,7 @@
<Compile Include="DataBinding\ChangeTracking\PropertyPath.cs" />
<Compile Include="DataBinding\ChangeTracking\TargettedProperty.cs" />
<Compile Include="Context\PerspexParserFactory.cs" />
<Compile Include="Parsers\SelectorGrammar.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="DataBinding\DataContextChangeSynchronizer.cs" />
<Compile Include="DataBinding\IPerspexPropertyBinder.cs" />

2
src/Markup/Perspex.Markup.Xaml/Properties/AssemblyInfo.cs

@ -2,5 +2,7 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System.Reflection;
using System.Runtime.CompilerServices;
[assembly: AssemblyTitle("Perspex.Markup.Xaml")]
[assembly: InternalsVisibleTo("Perspex.Markup.Xaml.UnitTests")]

2
src/Perspex.Styling/Styling/Selectors.cs

@ -78,7 +78,7 @@ namespace Perspex.Styling
return new Selector(
previous,
x => MatchTemplate(x, previous),
" /deep/ ",
" /template/ ",
inTemplate: true,
stopTraversal: true);
}

Loading…
Cancel
Save