Browse Source

Wrote binding expression parser by hand.

Sprache couldn't cope with it as it requires a left-recursive grammar.
pull/237/head
Steven Kirk 11 years ago
parent
commit
d43a79fab5
  1. 7
      src/Markup/Perspex.Markup/Binding/ExpressionNode.cs
  2. 85
      src/Markup/Perspex.Markup/Binding/ExpressionNodeBuilder.cs
  3. 24
      src/Markup/Perspex.Markup/Binding/ExpressionParseException.cs
  4. 5
      src/Markup/Perspex.Markup/Binding/IndexerNode.cs
  5. 5
      src/Markup/Perspex.Markup/Binding/LogicalNotNode.cs
  6. 63
      src/Markup/Perspex.Markup/Binding/Parsers/ArgumentListParser.cs
  7. 152
      src/Markup/Perspex.Markup/Binding/Parsers/ExpressionParser.cs
  8. 51
      src/Markup/Perspex.Markup/Binding/Parsers/IdentifierParser.cs
  9. 34
      src/Markup/Perspex.Markup/Binding/Parsers/LiteralParser.cs
  10. 31
      src/Markup/Perspex.Markup/Binding/Parsers/Reader.cs
  11. 3
      src/Markup/Perspex.Markup/Binding/PropertyAccessorNode.cs
  12. 18
      src/Markup/Perspex.Markup/Parsers/CSharp/BracketedArgumentListSyntax.cs
  13. 17
      src/Markup/Perspex.Markup/Parsers/CSharp/CSharpSyntaxTree.cs
  14. 19
      src/Markup/Perspex.Markup/Parsers/CSharp/ElementAccessExpressionSyntax.cs
  15. 15
      src/Markup/Perspex.Markup/Parsers/CSharp/ExpressionStatementSyntax.cs
  16. 9
      src/Markup/Perspex.Markup/Parsers/CSharp/ExpressionSyntax.cs
  17. 64
      src/Markup/Perspex.Markup/Parsers/CSharp/Grammar/ExpressionGrammar.cs
  18. 41
      src/Markup/Perspex.Markup/Parsers/CSharp/Grammar/IdentifierGrammar.cs
  19. 20
      src/Markup/Perspex.Markup/Parsers/CSharp/Grammar/LiteralGrammar.cs
  20. 17
      src/Markup/Perspex.Markup/Parsers/CSharp/IdentifierSyntax.cs
  21. 17
      src/Markup/Perspex.Markup/Parsers/CSharp/LiteralExpressionSyntax.cs
  22. 17
      src/Markup/Perspex.Markup/Parsers/CSharp/MemberAccessExpressionSyntax.cs
  23. 23
      src/Markup/Perspex.Markup/Parsers/CSharp/PrefixUnaryExpressionSyntax.cs
  24. 10
      src/Markup/Perspex.Markup/Parsers/CSharp/SyntaxKind.cs
  25. 9
      src/Markup/Perspex.Markup/Parsers/CSharp/SyntaxNode.cs
  26. 15
      src/Markup/Perspex.Markup/Parsers/CSharp/SyntaxToken.cs
  27. 27
      src/Markup/Perspex.Markup/Perspex.Markup.csproj
  28. 1
      src/Markup/Perspex.Markup/packages.config
  29. 7
      tests/Perspex.Markup.UnitTests/Binding/ExpressionNodeBuilderTests.cs

7
src/Markup/Perspex.Markup/Binding/ExpressionNode.cs

@ -14,12 +14,7 @@ namespace Perspex.Markup.Binding
private ExpressionValue _value = ExpressionValue.None;
public ExpressionNode(ExpressionNode next)
{
Next = next;
}
public ExpressionNode Next { get; }
public ExpressionNode Next { get; set; }
public object Target
{

85
src/Markup/Perspex.Markup/Binding/ExpressionNodeBuilder.cs

@ -2,12 +2,11 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
using Perspex.Markup.Parsers.CSharp;
using Perspex.Markup.Binding.Parsers;
namespace Perspex.Markup.Binding
{
internal class ExpressionNodeBuilder
internal static class ExpressionNodeBuilder
{
public static ExpressionNode Build(string expression)
{
@ -16,85 +15,15 @@ namespace Perspex.Markup.Binding
throw new ArgumentException("'expression' may not be empty.");
}
var syntax = CSharpSyntaxTree.ParseExpression(expression);
var reader = new Reader(expression);
var node = ExpressionParser.Parse(reader);
if (syntax != null)
if (!reader.End)
{
return Build(expression, syntax, null);
throw new ExpressionParseException(reader, "Expected end of expression.");
}
else
{
throw new Exception($"Invalid expression: {expression}");
}
}
private static ExpressionNode Build(string expression, SyntaxNode syntax, ExpressionNode next)
{
var expressionStatement = syntax as ExpressionStatementSyntax;
var identifier = syntax as IdentifierSyntax;
var memberAccess = syntax as MemberAccessExpressionSyntax;
var unaryExpression = syntax as PrefixUnaryExpressionSyntax;
var elementAccess = syntax as ElementAccessExpressionSyntax;
if (expressionStatement != null)
{
return Build(expression, expressionStatement.Expression, next);
}
else if (identifier != null)
{
next = new PropertyAccessorNode(next, identifier.Name);
}
else if (memberAccess != null)
{
next = Build(expression, memberAccess.Expression, next);
next = new PropertyAccessorNode(next, memberAccess.Member.Name);
}
else if (unaryExpression != null && unaryExpression.Kind() == SyntaxKind.LogicalNotExpression)
{
next = Build(expression, unaryExpression.Operand, next);
next = new LogicalNotNode(next);
}
else if (elementAccess != null)
{
next = Build(expression, elementAccess, next);
next = Build(expression, elementAccess.Expression, next);
}
else
{
throw new Exception($"Invalid expression: {expression}");
}
return next;
}
private static ExpressionNode Build(string expression, ElementAccessExpressionSyntax syntax, ExpressionNode next)
{
var argList = syntax.ArgumentList as BracketedArgumentListSyntax;
if (argList != null)
{
var args = new List<object>();
foreach (var arg in argList.Arguments)
{
var literal = arg as LiteralExpressionSyntax;
if (literal != null)
{
args.Add(literal.Value);
}
else
{
throw new Exception($"Invalid expression: {expression}");
}
}
return new ElementAccessorNode(next, args);
}
else
{
throw new Exception($"Invalid expression: {expression}");
}
return node;
}
}
}

24
src/Markup/Perspex.Markup/Binding/ExpressionParseException.cs

@ -0,0 +1,24 @@
// 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.Markup.Binding.Parsers;
namespace Perspex.Markup.Binding
{
public class ExpressionParseException : Exception
{
internal ExpressionParseException(int column, string message)
: base(message)
{
Column = column;
}
internal ExpressionParseException(Reader r, string message)
: this(r.Position, message)
{
}
public int Column { get; }
}
}

5
src/Markup/Perspex.Markup/Binding/ElementAccessorNode.cs → src/Markup/Perspex.Markup/Binding/IndexerNode.cs

@ -10,12 +10,11 @@ using System.Reflection;
namespace Perspex.Markup.Binding
{
internal class ElementAccessorNode : ExpressionNode
internal class IndexerNode : ExpressionNode
{
private int[] _intArgs;
public ElementAccessorNode(ExpressionNode next, IList<object> arguments)
: base(next)
public IndexerNode(IList<object> arguments)
{
Arguments = arguments;

5
src/Markup/Perspex.Markup/Binding/LogicalNotNode.cs

@ -9,11 +9,6 @@ namespace Perspex.Markup.Binding
{
internal class LogicalNotNode : ExpressionNode
{
public LogicalNotNode(ExpressionNode next)
: base(next)
{
}
public override bool SetValue(object value)
{
throw new NotSupportedException("Cannot set a negated binding.");

63
src/Markup/Perspex.Markup/Binding/Parsers/ArgumentListParser.cs

@ -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 System;
using System.Collections.Generic;
namespace Perspex.Markup.Binding.Parsers
{
internal static class ArgumentListParser
{
public static IList<object> Parse(Reader r, char open, char close)
{
if (r.Peek == open)
{
var result = new List<object>();
r.Take();
while (!r.End && r.Peek != close)
{
var literal = LiteralParser.Parse(r);
if (literal != null)
{
result.Add(literal);
}
else
{
throw new ExpressionParseException(r, "Expected integer.");
}
r.SkipWhitespace();
if (r.End)
{
throw new ExpressionParseException(r, "Expected ','.");
}
if (r.Peek != close)
{
if (r.Take() != ',')
{
throw new ExpressionParseException(r, "Expected ','.");
}
r.SkipWhitespace();
}
}
if (!r.End)
{
r.Take();
return result;
}
else
{
throw new ExpressionParseException(r, "Expected ']'.");
}
}
return null;
}
}
}

152
src/Markup/Perspex.Markup/Binding/Parsers/ExpressionParser.cs

@ -0,0 +1,152 @@
// 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.Collections.Generic;
namespace Perspex.Markup.Binding.Parsers
{
internal static class ExpressionParser
{
public static ExpressionNode Parse(Reader r)
{
var nodes = new List<ExpressionNode>();
var state = State.Start;
while (!r.End && state != State.End)
{
switch (state)
{
case State.Start:
state = ParseStart(r, nodes);
break;
case State.AfterMember:
state = ParseAfterMember(r, nodes);
break;
case State.BeforeMember:
state = ParseBeforeMember(r, nodes);
break;
default:
state = State.End;
break;
}
}
for (int n = 0; n < nodes.Count - 1; ++n)
{
nodes[n].Next = nodes[n + 1];
}
return nodes[0];
}
private static State ParseStart(Reader r, IList<ExpressionNode> nodes)
{
if (ParseNot(r))
{
nodes.Add(new LogicalNotNode());
return State.Start;
}
else
{
var identifier = IdentifierParser.Parse(r);
if (identifier != null)
{
nodes.Add(new PropertyAccessorNode(identifier));
return State.AfterMember;
}
}
return State.End;
}
private static State ParseAfterMember(Reader r, IList<ExpressionNode> nodes)
{
if (ParseMemberAccessor(r))
{
return State.BeforeMember;
}
else
{
var args = ArgumentListParser.Parse(r, '[', ']');
if (args != null)
{
if (args.Count == 0)
{
throw new ExpressionParseException(r, "Indexer may not be empty.");
}
nodes.Add(new IndexerNode(args));
return State.AfterMember;
}
}
return State.End;
}
private static State ParseBeforeMember(Reader r, IList<ExpressionNode> nodes)
{
var identifier = IdentifierParser.Parse(r);
if (identifier != null)
{
nodes.Add(new PropertyAccessorNode(identifier));
return State.AfterMember;
}
return State.End;
}
private static bool ParseNot(Reader r)
{
if (!r.End && r.Peek == '!')
{
r.Take();
return true;
}
else
{
return false;
}
}
private static bool ParseMemberAccessor(Reader r)
{
if (!r.End && r.Peek == '.')
{
r.Take();
return true;
}
else
{
return false;
}
}
private static bool ParseIndexer(Reader r)
{
if (!r.End && r.Peek == '[')
{
r.Take();
return true;
}
else
{
return false;
}
}
private enum State
{
Start,
AfterMember,
BeforeMember,
End,
}
}
}

51
src/Markup/Perspex.Markup/Binding/Parsers/IdentifierParser.cs

@ -0,0 +1,51 @@
// 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.Globalization;
using System.Text;
namespace Perspex.Markup.Binding.Parsers
{
internal static class IdentifierParser
{
public static string Parse(Reader r)
{
if (IsValidIdentifierStart(r.Peek))
{
var result = new StringBuilder();
while (!r.End && IsValidIdentifierChar(r.Peek))
{
result.Append(r.Take());
}
return result.ToString();
}
else
{
return null;
}
}
private static bool IsValidIdentifierStart(char c)
{
return char.IsLetter(c) || c == '_';
}
private static bool IsValidIdentifierChar(char c)
{
if (IsValidIdentifierStart(c))
{
return true;
}
else
{
var cat = CharUnicodeInfo.GetUnicodeCategory(c);
return cat == UnicodeCategory.NonSpacingMark ||
cat == UnicodeCategory.SpacingCombiningMark ||
cat == UnicodeCategory.ConnectorPunctuation ||
cat == UnicodeCategory.Format;
}
}
}
}

34
src/Markup/Perspex.Markup/Binding/Parsers/LiteralParser.cs

@ -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.Text;
namespace Perspex.Markup.Binding.Parsers
{
internal static class LiteralParser
{
public static object Parse(Reader r)
{
if (char.IsDigit(r.Peek))
{
StringBuilder result = new StringBuilder();
while (!r.End)
{
if (char.IsDigit(r.Peek))
{
result.Append(r.Take());
}
else
{
break;
}
}
return int.Parse(result.ToString());
}
return null;
}
}
}

31
src/Markup/Perspex.Markup/Binding/Parsers/Reader.cs

@ -0,0 +1,31 @@
// 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;
namespace Perspex.Markup.Binding.Parsers
{
internal class Reader
{
private string _s;
private int _i;
public Reader(string s)
{
_s = s;
}
public bool End => _i == _s.Length;
public char Peek => _s[_i];
public int Position => _i;
public char Take() => _s[_i++];
public void SkipWhitespace()
{
while (!End && char.IsWhiteSpace(Peek))
{
Take();
}
}
}
}

3
src/Markup/Perspex.Markup/Binding/PropertyAccessorNode.cs

@ -11,8 +11,7 @@ namespace Perspex.Markup.Binding
{
private PropertyInfo _propertyInfo;
public PropertyAccessorNode(ExpressionNode next, string propertyName)
: base(next)
public PropertyAccessorNode(string propertyName)
{
PropertyName = propertyName;
}

18
src/Markup/Perspex.Markup/Parsers/CSharp/BracketedArgumentListSyntax.cs

@ -1,18 +0,0 @@
// 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.Linq;
namespace Perspex.Markup.Parsers.CSharp
{
internal class BracketedArgumentListSyntax
{
public BracketedArgumentListSyntax(IEnumerable<ExpressionSyntax> arguments)
{
Arguments = arguments.ToList();
}
public IList<ExpressionSyntax> Arguments { get; }
}
}

17
src/Markup/Perspex.Markup/Parsers/CSharp/CSharpSyntaxTree.cs

@ -1,17 +0,0 @@
// 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.Markup.Parsers.CSharp.Grammar;
using Sprache;
namespace Perspex.Markup.Parsers.CSharp
{
public class CSharpSyntaxTree
{
internal static ExpressionStatementSyntax ParseExpression(string expression)
{
return ExpressionGrammar.ExpressionStatement().Parse(expression);
}
}
}

19
src/Markup/Perspex.Markup/Parsers/CSharp/ElementAccessExpressionSyntax.cs

@ -1,19 +0,0 @@
// 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.
namespace Perspex.Markup.Parsers.CSharp
{
internal class ElementAccessExpressionSyntax : ExpressionSyntax
{
public ElementAccessExpressionSyntax(
ExpressionSyntax expression,
BracketedArgumentListSyntax argumentList)
{
Expression = expression;
ArgumentList = argumentList;
}
public ExpressionSyntax Expression { get; }
public BracketedArgumentListSyntax ArgumentList { get; }
}
}

15
src/Markup/Perspex.Markup/Parsers/CSharp/ExpressionStatementSyntax.cs

@ -1,15 +0,0 @@
// 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.
namespace Perspex.Markup.Parsers.CSharp
{
internal class ExpressionStatementSyntax : SyntaxNode
{
public ExpressionStatementSyntax(ExpressionSyntax expression)
{
Expression = expression;
}
public ExpressionSyntax Expression { get; }
}
}

9
src/Markup/Perspex.Markup/Parsers/CSharp/ExpressionSyntax.cs

@ -1,9 +0,0 @@
// 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.
namespace Perspex.Markup.Parsers.CSharp
{
internal class ExpressionSyntax : SyntaxNode
{
}
}

64
src/Markup/Perspex.Markup/Parsers/CSharp/Grammar/ExpressionGrammar.cs

@ -1,64 +0,0 @@
// 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.Linq;
using Sprache;
namespace Perspex.Markup.Parsers.CSharp.Grammar
{
internal class ExpressionGrammar
{
public static Parser<ExpressionStatementSyntax> ExpressionStatement()
{
return from expression in Expression().End()
select new ExpressionStatementSyntax(expression);
}
public static Parser<ExpressionSyntax> Expression()
{
return LiteralGrammar.Literal()
.Or<ExpressionSyntax>(PrefixUnary())
.Or<ExpressionSyntax>(MemberAccess())
.Or<ExpressionSyntax>(ElementAccess())
.Or<ExpressionSyntax>(IdentifierGrammar.Identifier());
}
public static Parser<MemberAccessExpressionSyntax> MemberAccess()
{
return from identifier in IdentifierGrammar.Identifier()
from dot in Parse.Char('.')
from expression in Expression()
select new MemberAccessExpressionSyntax(expression, identifier);
}
public static Parser<ElementAccessExpressionSyntax> ElementAccess()
{
return from expression in IdentifierGrammar.Identifier()
from arguments in BracketedArgumentList('[', ']')
select new ElementAccessExpressionSyntax(expression, arguments);
}
public static Parser<BracketedArgumentListSyntax> BracketedArgumentList(
char openBracket,
char closeBracket)
{
return from open in Parse.Char(openBracket)
from arguments in Arguments()
from close in Parse.Char(closeBracket)
select new BracketedArgumentListSyntax(arguments);
}
public static Parser<IEnumerable<ExpressionSyntax>> Arguments()
{
return Expression().DelimitedBy(Parse.Char(',').Token());
}
public static Parser<PrefixUnaryExpressionSyntax> PrefixUnary()
{
return from bang in Parse.Char('!')
from operand in Expression()
select new PrefixUnaryExpressionSyntax(operand, SyntaxKind.LogicalNotExpression);
}
}
}

41
src/Markup/Perspex.Markup/Parsers/CSharp/Grammar/IdentifierGrammar.cs

@ -1,41 +0,0 @@
using System.Globalization;
using System.Linq;
using Sprache;
namespace Perspex.Markup.Parsers.CSharp.Grammar
{
internal class IdentifierGrammar
{
private static readonly Parser<char> CombiningCharacter = Parse.Char(
c =>
{
var cat = CharUnicodeInfo.GetUnicodeCategory(c);
return cat == UnicodeCategory.NonSpacingMark ||
cat == UnicodeCategory.SpacingCombiningMark;
},
"Connecting Character");
private static readonly Parser<char> ConnectingCharacter = Parse.Char(
c => CharUnicodeInfo.GetUnicodeCategory(c) == UnicodeCategory.ConnectorPunctuation,
"Connecting Character");
private static readonly Parser<char> FormattingCharacter = Parse.Char(
c => CharUnicodeInfo.GetUnicodeCategory(c) == UnicodeCategory.Format,
"Connecting Character");
private static readonly Parser<char> IdentifierStart = Parse.Letter.Or(Parse.Char('_'));
private static readonly Parser<char> IdentifierChar = Parse
.LetterOrDigit
.Or(ConnectingCharacter)
.Or(CombiningCharacter)
.Or(FormattingCharacter);
public static Parser<IdentifierSyntax> Identifier()
{
return from start in IdentifierStart.Once().Text()
from @char in IdentifierChar.Many().Text()
select new IdentifierSyntax(start + @char);
}
}
}

20
src/Markup/Perspex.Markup/Parsers/CSharp/Grammar/LiteralGrammar.cs

@ -1,20 +0,0 @@
using System.Globalization;
using System.Linq;
using Sprache;
namespace Perspex.Markup.Parsers.CSharp.Grammar
{
internal class LiteralGrammar
{
public static Parser<LiteralExpressionSyntax> Literal()
{
return Integer();
}
public static Parser<LiteralExpressionSyntax> Integer()
{
return from number in Parse.Number
select new LiteralExpressionSyntax(int.Parse(number), number);
}
}
}

17
src/Markup/Perspex.Markup/Parsers/CSharp/IdentifierSyntax.cs

@ -1,17 +0,0 @@
// 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;
namespace Perspex.Markup.Parsers.CSharp
{
internal class IdentifierSyntax : ExpressionSyntax
{
public IdentifierSyntax(string name)
{
Name = name;
}
public String Name { get; }
}
}

17
src/Markup/Perspex.Markup/Parsers/CSharp/LiteralExpressionSyntax.cs

@ -1,17 +0,0 @@
// 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.
namespace Perspex.Markup.Parsers.CSharp
{
internal class LiteralExpressionSyntax : ExpressionSyntax
{
public LiteralExpressionSyntax(object value, string valueText)
{
Value = value;
ValueText = valueText;
}
public object Value { get; }
public string ValueText { get; }
}
}

17
src/Markup/Perspex.Markup/Parsers/CSharp/MemberAccessExpressionSyntax.cs

@ -1,17 +0,0 @@
// 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.
namespace Perspex.Markup.Parsers.CSharp
{
internal class MemberAccessExpressionSyntax : ExpressionSyntax
{
public MemberAccessExpressionSyntax(ExpressionSyntax expression, IdentifierSyntax member)
{
Expression = expression;
Member = member;
}
public ExpressionSyntax Expression { get; }
public IdentifierSyntax Member { get; }
}
}

23
src/Markup/Perspex.Markup/Parsers/CSharp/PrefixUnaryExpressionSyntax.cs

@ -1,23 +0,0 @@
// 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.
namespace Perspex.Markup.Parsers.CSharp
{
internal class PrefixUnaryExpressionSyntax : ExpressionSyntax
{
private SyntaxKind _kind;
public PrefixUnaryExpressionSyntax(ExpressionSyntax operand, SyntaxKind kind)
{
Operand = operand;
_kind = kind;
}
public ExpressionSyntax Operand { get; }
public SyntaxKind Kind()
{
return _kind;
}
}
}

10
src/Markup/Perspex.Markup/Parsers/CSharp/SyntaxKind.cs

@ -1,10 +0,0 @@
// 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.
namespace Perspex.Markup.Parsers.CSharp
{
internal enum SyntaxKind
{
LogicalNotExpression,
}
}

9
src/Markup/Perspex.Markup/Parsers/CSharp/SyntaxNode.cs

@ -1,9 +0,0 @@
// 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.
namespace Perspex.Markup.Parsers.CSharp
{
internal class SyntaxNode
{
}
}

15
src/Markup/Perspex.Markup/Parsers/CSharp/SyntaxToken.cs

@ -1,15 +0,0 @@
// 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.
namespace Perspex.Markup.Parsers.CSharp
{
internal class SyntaxToken
{
public SyntaxToken(string valueText)
{
ValueText = valueText;
}
public string ValueText { get; }
}
}

27
src/Markup/Perspex.Markup/Perspex.Markup.csproj

@ -35,34 +35,21 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="Binding\ExpressionNodeBuilder.cs" />
<Compile Include="Binding\ExpressionParseException.cs" />
<Compile Include="Binding\ExpressionValue.cs" />
<Compile Include="Binding\LogicalNotNode.cs" />
<Compile Include="Binding\ElementAccessorNode.cs" />
<Compile Include="Binding\IndexerNode.cs" />
<Compile Include="Binding\Parsers\ArgumentListParser.cs" />
<Compile Include="Binding\Parsers\LiteralParser.cs" />
<Compile Include="Binding\Parsers\IdentifierParser.cs" />
<Compile Include="Binding\Parsers\ExpressionParser.cs" />
<Compile Include="Binding\Parsers\Reader.cs" />
<Compile Include="Binding\PropertyAccessorNode.cs" />
<Compile Include="Binding\ExpressionNode.cs" />
<Compile Include="Binding\ExpressionObserver.cs" />
<Compile Include="Parsers\CSharp\BracketedArgumentListSyntax.cs" />
<Compile Include="Parsers\CSharp\CSharpSyntaxTree.cs" />
<Compile Include="Parsers\CSharp\ElementAccessExpressionSyntax.cs" />
<Compile Include="Parsers\CSharp\ExpressionSyntax.cs" />
<Compile Include="Parsers\CSharp\ExpressionStatementSyntax.cs" />
<Compile Include="Parsers\CSharp\Grammar\ExpressionGrammar.cs" />
<Compile Include="Parsers\CSharp\Grammar\IdentifierGrammar.cs" />
<Compile Include="Parsers\CSharp\Grammar\LiteralGrammar.cs" />
<Compile Include="Parsers\CSharp\IdentifierSyntax.cs" />
<Compile Include="Parsers\CSharp\LiteralExpressionSyntax.cs" />
<Compile Include="Parsers\CSharp\MemberAccessExpressionSyntax.cs" />
<Compile Include="Parsers\CSharp\PrefixUnaryExpressionSyntax.cs" />
<Compile Include="Parsers\CSharp\SyntaxKind.cs" />
<Compile Include="Parsers\CSharp\SyntaxToken.cs" />
<Compile Include="Parsers\CSharp\SyntaxNode.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="Sprache, Version=2.0.0.47, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\Sprache.2.0.0.47\lib\portable-net4+netcore45+win8+wp8+sl5+MonoAndroid1+MonoTouch1\Sprache.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Reactive.Core, Version=2.2.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\Rx-Core.2.2.5\lib\portable-windows8+net45+wp8\System.Reactive.Core.dll</HintPath>
<Private>True</Private>

1
src/Markup/Perspex.Markup/packages.config

@ -5,5 +5,4 @@
<package id="Rx-Linq" version="2.2.5" targetFramework="portable45-net45+win8" />
<package id="Rx-Main" version="2.2.5" targetFramework="portable45-net45+win8" />
<package id="Rx-PlatformServices" version="2.2.5" targetFramework="portable45-net45+win8" />
<package id="Sprache" version="2.0.0.47" targetFramework="portable45-net45+win8" />
</packages>

7
tests/Perspex.Markup.UnitTests/Binding/ExpressionNodeBuilderTests.cs

@ -63,6 +63,7 @@ namespace Perspex.Markup.UnitTests.Binding
Assert.Equal(2, result.Count);
AssertIsProperty(result[0], "Foo");
AssertIsIndexer(result[1], 15);
Assert.IsType<IndexerNode>(result[1]);
}
[Fact]
@ -90,7 +91,7 @@ namespace Perspex.Markup.UnitTests.Binding
{
var result = ToList(ExpressionNodeBuilder.Build("Foo[15][16]"));
Assert.Equal(2, result.Count);
Assert.Equal(3, result.Count);
AssertIsProperty(result[0], "Foo");
AssertIsIndexer(result[1], 15);
AssertIsIndexer(result[2], 16);
@ -118,9 +119,9 @@ namespace Perspex.Markup.UnitTests.Binding
private void AssertIsIndexer(ExpressionNode node, params object[] args)
{
Assert.IsType<ElementAccessorNode>(node);
Assert.IsType<IndexerNode>(node);
var e = (ElementAccessorNode)node;
var e = (IndexerNode)node;
Assert.Equal(e.Arguments.ToArray(), args.ToArray());
}

Loading…
Cancel
Save