More careful parsing of braces and brackets inside array element lists
This commit is contained in:
parent
52a85be26c
commit
01dda0cf6f
@ -253,5 +253,102 @@ namespace Parser.Tests
|
|||||||
Assert.AreEqual(f.InputDescription, null);
|
Assert.AreEqual(f.InputDescription, null);
|
||||||
Assert.AreEqual(text, actual.FullText);
|
Assert.AreEqual(text, actual.FullText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ParseCellArrayWithCellArrayLiteralInside()
|
||||||
|
{
|
||||||
|
var text = "{1 2 a {3}}";
|
||||||
|
var sut = CreateParser(text);
|
||||||
|
var actual = sut.ParseExpression();
|
||||||
|
Assert.IsInstanceOf<CellArrayLiteralExpressionNode>(actual);
|
||||||
|
var a = (CellArrayLiteralExpressionNode) actual;
|
||||||
|
Assert.AreEqual(4, a.Elements.Elements.Count);
|
||||||
|
Assert.AreEqual(text, actual.FullText);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ParseCellArrayWithCellArrayAccessInside()
|
||||||
|
{
|
||||||
|
var text = "{1 2 a{3}}";
|
||||||
|
var sut = CreateParser(text);
|
||||||
|
var actual = sut.ParseExpression();
|
||||||
|
Assert.IsInstanceOf<CellArrayLiteralExpressionNode>(actual);
|
||||||
|
var a = (CellArrayLiteralExpressionNode) actual;
|
||||||
|
Assert.AreEqual(3, a.Elements.Elements.Count);
|
||||||
|
Assert.AreEqual(text, actual.FullText);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ParseCellArrayWithElementInBracketsInside()
|
||||||
|
{
|
||||||
|
var text = "{1 2 a (3)}";
|
||||||
|
var sut = CreateParser(text);
|
||||||
|
var actual = sut.ParseExpression();
|
||||||
|
Assert.IsInstanceOf<CellArrayLiteralExpressionNode>(actual);
|
||||||
|
var a = (CellArrayLiteralExpressionNode) actual;
|
||||||
|
Assert.AreEqual(4, a.Elements.Elements.Count);
|
||||||
|
Assert.AreEqual(text, actual.FullText);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ParseCellArrayWithFunctionCallInside()
|
||||||
|
{
|
||||||
|
var text = "{1 2 a(3)}";
|
||||||
|
var sut = CreateParser(text);
|
||||||
|
var actual = sut.ParseExpression();
|
||||||
|
Assert.IsInstanceOf<CellArrayLiteralExpressionNode>(actual);
|
||||||
|
var a = (CellArrayLiteralExpressionNode) actual;
|
||||||
|
Assert.AreEqual(3, a.Elements.Elements.Count);
|
||||||
|
Assert.AreEqual(text, actual.FullText);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ParseArrayWithCellArrayLiteralInside()
|
||||||
|
{
|
||||||
|
var text = "[1 2 a {3}]";
|
||||||
|
var sut = CreateParser(text);
|
||||||
|
var actual = sut.ParseExpression();
|
||||||
|
Assert.IsInstanceOf<ArrayLiteralExpressionNode>(actual);
|
||||||
|
var a = (ArrayLiteralExpressionNode) actual;
|
||||||
|
Assert.AreEqual(4, a.Elements.Elements.Count);
|
||||||
|
Assert.AreEqual(text, actual.FullText);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ParseArrayWithCellArrayAccessInside()
|
||||||
|
{
|
||||||
|
var text = "[1 2 a{3}]";
|
||||||
|
var sut = CreateParser(text);
|
||||||
|
var actual = sut.ParseExpression();
|
||||||
|
Assert.IsInstanceOf<ArrayLiteralExpressionNode>(actual);
|
||||||
|
var a = (ArrayLiteralExpressionNode) actual;
|
||||||
|
Assert.AreEqual(3, a.Elements.Elements.Count);
|
||||||
|
Assert.AreEqual(text, actual.FullText);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ParseArrayWithElementInBracketsInside()
|
||||||
|
{
|
||||||
|
var text = "[1 2 a (3)]";
|
||||||
|
var sut = CreateParser(text);
|
||||||
|
var actual = sut.ParseExpression();
|
||||||
|
Assert.IsInstanceOf<ArrayLiteralExpressionNode>(actual);
|
||||||
|
var a = (ArrayLiteralExpressionNode) actual;
|
||||||
|
Assert.AreEqual(4, a.Elements.Elements.Count);
|
||||||
|
Assert.AreEqual(text, actual.FullText);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ParseArrayWithFunctionCallInside()
|
||||||
|
{
|
||||||
|
var text = "[1 2 a(3)]";
|
||||||
|
var sut = CreateParser(text);
|
||||||
|
var actual = sut.ParseExpression();
|
||||||
|
Assert.IsInstanceOf<ArrayLiteralExpressionNode>(actual);
|
||||||
|
var a = (ArrayLiteralExpressionNode) actual;
|
||||||
|
Assert.AreEqual(3, a.Elements.Elements.Count);
|
||||||
|
Assert.AreEqual(text, actual.FullText);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -282,28 +282,32 @@ namespace Parser
|
|||||||
throw new ParsingException($"Unexpected token {CurrentToken.PureToken} at {CurrentToken.PureToken.Position}.");
|
throw new ParsingException($"Unexpected token {CurrentToken.PureToken} at {CurrentToken.PureToken.Position}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExpressionNode ParsePostfix(ExpressionNode expression)
|
private ExpressionNode ParsePostfix(ParseOptions options, ExpressionNode expression)
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
var token = CurrentToken;
|
var token = CurrentToken;
|
||||||
switch(token.Kind) {
|
switch(token.Kind) {
|
||||||
case TokenKind.OpeningBrace: // cell array element access
|
case TokenKind.OpeningBrace: // cell array element access
|
||||||
if (expression.TrailingTrivia.Any())
|
if (options.ParsingArrayElements && expression.TrailingTrivia.Any())
|
||||||
{
|
{
|
||||||
return expression;
|
return expression;
|
||||||
}
|
}
|
||||||
var openingBrace = EatToken();
|
var openingBrace = EatToken();
|
||||||
var index = ParseExpression();
|
var indices = ParseCellArrayElementList();
|
||||||
var closingBrace = EatToken(TokenKind.ClosingBrace);
|
var closingBrace = EatToken(TokenKind.ClosingBrace);
|
||||||
expression = Factory.CellArrayElementAccessExpression(
|
expression = Factory.CellArrayElementAccessExpression(
|
||||||
expression,
|
expression,
|
||||||
Factory.Token(openingBrace),
|
Factory.Token(openingBrace),
|
||||||
index,
|
indices,
|
||||||
Factory.Token(closingBrace)
|
Factory.Token(closingBrace)
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case TokenKind.OpeningBracket: // function call
|
case TokenKind.OpeningBracket: // function call
|
||||||
|
if (options.ParsingArrayElements && expression.TrailingTrivia.Any())
|
||||||
|
{
|
||||||
|
return expression;
|
||||||
|
}
|
||||||
var openingBracket = EatToken();
|
var openingBracket = EatToken();
|
||||||
var parameters = ParseFunctionCallParameterList();
|
var parameters = ParseFunctionCallParameterList();
|
||||||
var closingBracket = EatToken(TokenKind.ClosingBracket);
|
var closingBracket = EatToken(TokenKind.ClosingBracket);
|
||||||
@ -355,7 +359,7 @@ namespace Parser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var expression = ParseExpression();
|
var expression = ParseExpression(new ParseOptions {ParsingArrayElements = true});
|
||||||
if (expression != null)
|
if (expression != null)
|
||||||
{
|
{
|
||||||
nodes.Add(expression);
|
nodes.Add(expression);
|
||||||
@ -381,7 +385,7 @@ namespace Parser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes.Add(ParseExpression());
|
nodes.Add(ParseExpression(new ParseOptions {ParsingArrayElements = true}));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Factory.ArrayElementList(nodes);
|
return Factory.ArrayElementList(nodes);
|
||||||
@ -420,7 +424,7 @@ namespace Parser
|
|||||||
closeParen);
|
closeParen);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExpressionNode ParseTerm()
|
private ExpressionNode ParseTerm(ParseOptions options)
|
||||||
{
|
{
|
||||||
var token = CurrentToken;
|
var token = CurrentToken;
|
||||||
ExpressionNode expression = null;
|
ExpressionNode expression = null;
|
||||||
@ -460,12 +464,24 @@ namespace Parser
|
|||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return ParsePostfix(expression);
|
return ParsePostfix(options, expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal struct ParseOptions
|
||||||
|
{
|
||||||
|
public bool ParsingArrayElements { get; set; }
|
||||||
|
|
||||||
|
public static ParseOptions Default = new ParseOptions { ParsingArrayElements = false };
|
||||||
}
|
}
|
||||||
|
|
||||||
public ExpressionNode ParseExpression()
|
public ExpressionNode ParseExpression()
|
||||||
{
|
{
|
||||||
return ParseSubExpression(Precedence.Expression);
|
return ParseExpression(ParseOptions.Default);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ExpressionNode ParseExpression(ParseOptions options)
|
||||||
|
{
|
||||||
|
return ParseSubExpression(options, Precedence.Expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsUnaryOperator(TokenKind kind)
|
private bool IsUnaryOperator(TokenKind kind)
|
||||||
@ -533,8 +549,8 @@ namespace Parser
|
|||||||
throw new ArgumentException(nameof(kind));
|
throw new ArgumentException(nameof(kind));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExpressionNode ParseSubExpression(Precedence precedence)
|
private ExpressionNode ParseSubExpression(ParseOptions options, Precedence precedence)
|
||||||
{
|
{
|
||||||
ExpressionNode lhs = null;
|
ExpressionNode lhs = null;
|
||||||
if (IsUnaryOperator(CurrentToken.Kind))
|
if (IsUnaryOperator(CurrentToken.Kind))
|
||||||
@ -542,12 +558,12 @@ namespace Parser
|
|||||||
var operation = EatToken();
|
var operation = EatToken();
|
||||||
var unaryTokenKind = ConvertToUnaryTokenKind(operation.Kind);
|
var unaryTokenKind = ConvertToUnaryTokenKind(operation.Kind);
|
||||||
var newPrecedence = GetPrecedence(unaryTokenKind);
|
var newPrecedence = GetPrecedence(unaryTokenKind);
|
||||||
var operand = ParseSubExpression(newPrecedence);
|
var operand = ParseSubExpression(options, newPrecedence);
|
||||||
lhs = Factory.UnaryPrefixOperationExpression(Factory.Token(operation), operand);
|
lhs = Factory.UnaryPrefixOperationExpression(Factory.Token(operation), operand);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
lhs = ParseTerm();
|
lhs = ParseTerm(options);
|
||||||
}
|
}
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
@ -566,7 +582,7 @@ namespace Parser
|
|||||||
}
|
}
|
||||||
|
|
||||||
EatToken();
|
EatToken();
|
||||||
var rhs = ParseSubExpression(newPrecedence);
|
var rhs = ParseSubExpression(options, newPrecedence);
|
||||||
if (rhs == null && token.Kind == TokenKind.Colon) // for parsing things like a{:}
|
if (rhs == null && token.Kind == TokenKind.Colon) // for parsing things like a{:}
|
||||||
{
|
{
|
||||||
rhs = Factory.EmptyExpression();
|
rhs = Factory.EmptyExpression();
|
||||||
|
@ -264,15 +264,15 @@ namespace Parser
|
|||||||
public CellArrayElementAccessExpressionNode CellArrayElementAccessExpression(
|
public CellArrayElementAccessExpressionNode CellArrayElementAccessExpression(
|
||||||
ExpressionNode cellArray,
|
ExpressionNode cellArray,
|
||||||
TokenNode openingBrace,
|
TokenNode openingBrace,
|
||||||
ExpressionNode index,
|
ArrayElementListNode indices,
|
||||||
TokenNode closingBrace)
|
TokenNode closingBrace)
|
||||||
{
|
{
|
||||||
var children = new List<SyntaxNode> {cellArray, openingBrace, index, closingBrace};
|
var children = new List<SyntaxNode> {cellArray, openingBrace, indices, closingBrace};
|
||||||
var result = new CellArrayElementAccessExpressionNode(
|
var result = new CellArrayElementAccessExpressionNode(
|
||||||
children,
|
children,
|
||||||
cellArray,
|
cellArray,
|
||||||
openingBrace,
|
openingBrace,
|
||||||
index,
|
indices,
|
||||||
closingBrace);
|
closingBrace);
|
||||||
SetParent(result);
|
SetParent(result);
|
||||||
return result;
|
return result;
|
||||||
|
@ -340,19 +340,19 @@ namespace Parser
|
|||||||
{
|
{
|
||||||
public ExpressionNode CellArray { get; }
|
public ExpressionNode CellArray { get; }
|
||||||
public TokenNode OpeningBrace { get; }
|
public TokenNode OpeningBrace { get; }
|
||||||
public ExpressionNode Index { get; }
|
public ArrayElementListNode Indices { get; }
|
||||||
public TokenNode ClosingBrace { get; }
|
public TokenNode ClosingBrace { get; }
|
||||||
|
|
||||||
public CellArrayElementAccessExpressionNode(
|
public CellArrayElementAccessExpressionNode(
|
||||||
List<SyntaxNode> children,
|
List<SyntaxNode> children,
|
||||||
ExpressionNode cellArray,
|
ExpressionNode cellArray,
|
||||||
TokenNode openingBrace,
|
TokenNode openingBrace,
|
||||||
ExpressionNode index,
|
ArrayElementListNode indices,
|
||||||
TokenNode closingBrace) : base(children)
|
TokenNode closingBrace) : base(children)
|
||||||
{
|
{
|
||||||
CellArray = cellArray;
|
CellArray = cellArray;
|
||||||
OpeningBrace = openingBrace;
|
OpeningBrace = openingBrace;
|
||||||
Index = index;
|
Indices = indices;
|
||||||
ClosingBrace = closingBrace;
|
ClosingBrace = closingBrace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user