Browse Source

Imrpove nth-child parsing

pull/6381/head
Max Katz 4 years ago
parent
commit
d64a700b4f
  1. 56
      src/Markup/Avalonia.Markup/Markup/Parsers/SelectorGrammar.cs
  2. 69
      tests/Avalonia.Markup.UnitTests/Parsers/SelectorGrammarTests.cs

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

@ -350,12 +350,28 @@ namespace Avalonia.Markup.Parsers
}
else
{
var stepOrOffsetSpan = r.TakeWhile(c => c != ')' && c != 'n');
if (!int.TryParse(stepOrOffsetSpan.ToString().Trim(), out var stepOrOffset))
r.SkipWhitespace();
var stepOrOffset = 0;
var stepOrOffsetStr = r.TakeWhile(c => char.IsDigit(c) || c == '-' || c == '+').ToString();
if (stepOrOffsetStr.Length == 0
|| (stepOrOffsetStr.Length == 1
&& stepOrOffsetStr[0] == '+'))
{
stepOrOffset = 1;
}
else if (stepOrOffsetStr.Length == 1
&& stepOrOffsetStr[0] == '-')
{
stepOrOffset = -1;
}
else if (!int.TryParse(stepOrOffsetStr.ToString(), out stepOrOffset))
{
throw new ExpressionParseException(r.Position, "Couldn't parse nth-child step or offset value. Integer was expected.");
}
r.SkipWhitespace();
if (r.Peek == ')')
{
step = 0;
@ -365,13 +381,41 @@ namespace Avalonia.Markup.Parsers
{
step = stepOrOffset;
if (r.Peek != 'n')
{
throw new ExpressionParseException(r.Position, "Couldn't parse nth-child step value, \"xn+y\" pattern was expected.");
}
r.Skip(1); // skip 'n'
var offsetSpan = r.TakeUntil(')').TrimStart();
if (offsetSpan.Length != 0
&& !int.TryParse(offsetSpan.ToString().Trim(), out offset))
r.SkipWhitespace();
if (r.Peek != ')')
{
throw new ExpressionParseException(r.Position, "Couldn't parse nth-child offset value. Integer was expected.");
int sign;
var nextChar = r.Take();
if (nextChar == '+')
{
sign = 1;
}
else if (nextChar == '-')
{
sign = -1;
}
else
{
throw new ExpressionParseException(r.Position, "Couldn't parse nth-child sign. '+' or '-' was expected.");
}
r.SkipWhitespace();
if (sign != 0
&& !int.TryParse(r.TakeUntil(')').ToString(), out offset))
{
throw new ExpressionParseException(r.Position, "Couldn't parse nth-child offset value. Integer was expected.");
}
offset *= sign;
}
}
}

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

@ -236,6 +236,75 @@ namespace Avalonia.Markup.UnitTests.Parsers
result);
}
[Theory]
[InlineData(":nth-child(xn+2)")]
[InlineData(":nth-child(2n+b)")]
[InlineData(":nth-child(2n+)")]
[InlineData(":nth-child(2na)")]
[InlineData(":nth-child(2x+1)")]
public void NthChild_Invalid_Inputs(string input)
{
Assert.Throws<ExpressionParseException>(() => SelectorGrammar.Parse(input));
}
[Theory]
[InlineData(":nth-child(+1)", 0, 1)]
[InlineData(":nth-child(1)", 0, 1)]
[InlineData(":nth-child(-1)", 0, -1)]
[InlineData(":nth-child(2n+1)", 2, 1)]
[InlineData(":nth-child(n)", 1, 0)]
[InlineData(":nth-child(+n)", 1, 0)]
[InlineData(":nth-child(-n)", -1, 0)]
[InlineData(":nth-child(-2n)", -2, 0)]
[InlineData(":nth-child(n+5)", 1, 5)]
[InlineData(":nth-child(n-5)", 1, -5)]
[InlineData(":nth-child( 2n + 1 )", 2, 1)]
[InlineData(":nth-child( 2n - 1 )", 2, -1)]
public void NthChild_Variations(string input, int step, int offset)
{
var result = SelectorGrammar.Parse(input);
Assert.Equal(
new SelectorGrammar.ISyntax[]
{
new SelectorGrammar.NthChildSyntax()
{
Step = step,
Offset = offset
}
},
result);
}
[Theory]
[InlineData(":nth-last-child(+1)", 0, 1)]
[InlineData(":nth-last-child(1)", 0, 1)]
[InlineData(":nth-last-child(-1)", 0, -1)]
[InlineData(":nth-last-child(2n+1)", 2, 1)]
[InlineData(":nth-last-child(n)", 1, 0)]
[InlineData(":nth-last-child(+n)", 1, 0)]
[InlineData(":nth-last-child(-n)", -1, 0)]
[InlineData(":nth-last-child(-2n)", -2, 0)]
[InlineData(":nth-last-child(n+5)", 1, 5)]
[InlineData(":nth-last-child(n-5)", 1, -5)]
[InlineData(":nth-last-child( 2n + 1 )", 2, 1)]
[InlineData(":nth-last-child( 2n - 1 )", 2, -1)]
public void NthLastChild_Variations(string input, int step, int offset)
{
var result = SelectorGrammar.Parse(input);
Assert.Equal(
new SelectorGrammar.ISyntax[]
{
new SelectorGrammar.NthLastChildSyntax()
{
Step = step,
Offset = offset
}
},
result);
}
[Fact]
public void OfType_NthChild()
{

Loading…
Cancel
Save