Browse Source

Parse nesting selector.

pull/8024/head
Steven Kirk 4 years ago
parent
commit
a506737a0f
  1. 30
      src/Markup/Avalonia.Markup/Markup/Parsers/SelectorGrammar.cs
  2. 139
      tests/Avalonia.Markup.UnitTests/Parsers/SelectorGrammarTests.cs

30
src/Markup/Avalonia.Markup/Markup/Parsers/SelectorGrammar.cs

@ -46,7 +46,7 @@ namespace Avalonia.Markup.Parsers
switch (state)
{
case State.Start:
state = ParseStart(ref r);
(state, syntax) = ParseStart(ref r);
break;
case State.Middle:
(state, syntax) = ParseMiddle(ref r, end);
@ -93,27 +93,31 @@ namespace Avalonia.Markup.Parsers
return selector;
}
private static State ParseStart(ref CharacterReader r)
private static (State, ISyntax?) ParseStart(ref CharacterReader r)
{
r.SkipWhitespace();
if (r.End)
{
return State.End;
return (State.End, null);
}
if (r.TakeIf(':'))
{
return State.Colon;
return (State.Colon, null);
}
else if (r.TakeIf('.'))
{
return State.Class;
return (State.Class, null);
}
else if (r.TakeIf('#'))
{
return State.Name;
return (State.Name, null);
}
else if (r.TakeIf('&'))
{
return (State.CanHaveType, new NestingSyntax());
}
return State.TypeName;
return (State.TypeName, null);
}
private static (State, ISyntax?) ParseMiddle(ref CharacterReader r, char? end)
@ -142,6 +146,10 @@ namespace Avalonia.Markup.Parsers
{
return (State.Start, new CommaSyntax());
}
else if (r.TakeIf('&'))
{
return (State.CanHaveType, new NestingSyntax());
}
else if (end.HasValue && !r.End && r.Peek == end.Value)
{
return (State.End, null);
@ -635,5 +643,13 @@ namespace Avalonia.Markup.Parsers
return obj is CommaSyntax or;
}
}
public class NestingSyntax : ISyntax
{
public override bool Equals(object? obj)
{
return obj is NestingSyntax;
}
}
}
}

139
tests/Avalonia.Markup.UnitTests/Parsers/SelectorGrammarTests.cs

@ -469,6 +469,145 @@ namespace Avalonia.Markup.UnitTests.Parsers
result);
}
[Fact]
public void Nesting_Class()
{
var result = SelectorGrammar.Parse("&.foo");
Assert.Equal(
new SelectorGrammar.ISyntax[]
{
new SelectorGrammar.NestingSyntax(),
new SelectorGrammar.ClassSyntax { Class = "foo" },
},
result);
}
[Fact]
public void Nesting_Child_Class()
{
var result = SelectorGrammar.Parse("& > .foo");
Assert.Equal(
new SelectorGrammar.ISyntax[]
{
new SelectorGrammar.NestingSyntax(),
new SelectorGrammar.ChildSyntax { },
new SelectorGrammar.ClassSyntax { Class = "foo" },
},
result);
}
[Fact]
public void Nesting_Descendant_Class()
{
var result = SelectorGrammar.Parse("& .foo");
Assert.Equal(
new SelectorGrammar.ISyntax[]
{
new SelectorGrammar.NestingSyntax(),
new SelectorGrammar.DescendantSyntax { },
new SelectorGrammar.ClassSyntax { Class = "foo" },
},
result);
}
[Fact]
public void Nesting_Template_Class()
{
var result = SelectorGrammar.Parse("& /template/ .foo");
Assert.Equal(
new SelectorGrammar.ISyntax[]
{
new SelectorGrammar.NestingSyntax(),
new SelectorGrammar.TemplateSyntax { },
new SelectorGrammar.ClassSyntax { Class = "foo" },
},
result);
}
[Fact]
public void OfType_Template_Nesting()
{
var result = SelectorGrammar.Parse("Button /template/ &");
Assert.Equal(
new SelectorGrammar.ISyntax[]
{
new SelectorGrammar.OfTypeSyntax { TypeName = "Button" },
new SelectorGrammar.TemplateSyntax { },
new SelectorGrammar.NestingSyntax(),
},
result);
}
[Fact]
public void Nesting_Property()
{
var result = SelectorGrammar.Parse("&[Foo=bar]");
Assert.Equal(
new SelectorGrammar.ISyntax[]
{
new SelectorGrammar.NestingSyntax(),
new SelectorGrammar.PropertySyntax { Property = "Foo", Value = "bar" },
},
result);
}
[Fact]
public void Not_Nesting()
{
var result = SelectorGrammar.Parse(":not(&)");
Assert.Equal(
new SelectorGrammar.ISyntax[]
{
new SelectorGrammar.NotSyntax
{
Argument = new[] { new SelectorGrammar.NestingSyntax() },
}
},
result);
}
[Fact]
public void Nesting_NthChild()
{
var result = SelectorGrammar.Parse("&:nth-child(2n+1)");
Assert.Equal(
new SelectorGrammar.ISyntax[]
{
new SelectorGrammar.NestingSyntax(),
new SelectorGrammar.NthChildSyntax()
{
Step = 2,
Offset = 1
}
},
result);
}
[Fact]
public void Nesting_Comma_Nesting_Class()
{
var result = SelectorGrammar.Parse("&, &.foo");
Assert.Equal(
new SelectorGrammar.ISyntax[]
{
new SelectorGrammar.NestingSyntax(),
new SelectorGrammar.CommaSyntax(),
new SelectorGrammar.NestingSyntax(),
new SelectorGrammar.ClassSyntax { Class = "foo" },
},
result);
}
[Fact]
public void Namespace_Alone_Fails()
{

Loading…
Cancel
Save