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(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}.");
|
||||
}
|
||||
|
||||
private ExpressionNode ParsePostfix(ExpressionNode expression)
|
||||
private ExpressionNode ParsePostfix(ParseOptions options, ExpressionNode expression)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
var token = CurrentToken;
|
||||
switch(token.Kind) {
|
||||
case TokenKind.OpeningBrace: // cell array element access
|
||||
if (expression.TrailingTrivia.Any())
|
||||
if (options.ParsingArrayElements && expression.TrailingTrivia.Any())
|
||||
{
|
||||
return expression;
|
||||
}
|
||||
var openingBrace = EatToken();
|
||||
var index = ParseExpression();
|
||||
var indices = ParseCellArrayElementList();
|
||||
var closingBrace = EatToken(TokenKind.ClosingBrace);
|
||||
expression = Factory.CellArrayElementAccessExpression(
|
||||
expression,
|
||||
Factory.Token(openingBrace),
|
||||
index,
|
||||
indices,
|
||||
Factory.Token(closingBrace)
|
||||
);
|
||||
break;
|
||||
case TokenKind.OpeningBracket: // function call
|
||||
if (options.ParsingArrayElements && expression.TrailingTrivia.Any())
|
||||
{
|
||||
return expression;
|
||||
}
|
||||
var openingBracket = EatToken();
|
||||
var parameters = ParseFunctionCallParameterList();
|
||||
var closingBracket = EatToken(TokenKind.ClosingBracket);
|
||||
@ -355,7 +359,7 @@ namespace Parser
|
||||
}
|
||||
}
|
||||
|
||||
var expression = ParseExpression();
|
||||
var expression = ParseExpression(new ParseOptions {ParsingArrayElements = true});
|
||||
if (expression != null)
|
||||
{
|
||||
nodes.Add(expression);
|
||||
@ -381,7 +385,7 @@ namespace Parser
|
||||
}
|
||||
}
|
||||
|
||||
nodes.Add(ParseExpression());
|
||||
nodes.Add(ParseExpression(new ParseOptions {ParsingArrayElements = true}));
|
||||
}
|
||||
|
||||
return Factory.ArrayElementList(nodes);
|
||||
@ -420,7 +424,7 @@ namespace Parser
|
||||
closeParen);
|
||||
}
|
||||
|
||||
private ExpressionNode ParseTerm()
|
||||
private ExpressionNode ParseTerm(ParseOptions options)
|
||||
{
|
||||
var token = CurrentToken;
|
||||
ExpressionNode expression = null;
|
||||
@ -460,12 +464,24 @@ namespace Parser
|
||||
{
|
||||
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()
|
||||
{
|
||||
return ParseSubExpression(Precedence.Expression);
|
||||
return ParseExpression(ParseOptions.Default);
|
||||
}
|
||||
|
||||
private ExpressionNode ParseExpression(ParseOptions options)
|
||||
{
|
||||
return ParseSubExpression(options, Precedence.Expression);
|
||||
}
|
||||
|
||||
private bool IsUnaryOperator(TokenKind kind)
|
||||
@ -533,8 +549,8 @@ namespace Parser
|
||||
throw new ArgumentException(nameof(kind));
|
||||
}
|
||||
}
|
||||
|
||||
private ExpressionNode ParseSubExpression(Precedence precedence)
|
||||
|
||||
private ExpressionNode ParseSubExpression(ParseOptions options, Precedence precedence)
|
||||
{
|
||||
ExpressionNode lhs = null;
|
||||
if (IsUnaryOperator(CurrentToken.Kind))
|
||||
@ -542,12 +558,12 @@ namespace Parser
|
||||
var operation = EatToken();
|
||||
var unaryTokenKind = ConvertToUnaryTokenKind(operation.Kind);
|
||||
var newPrecedence = GetPrecedence(unaryTokenKind);
|
||||
var operand = ParseSubExpression(newPrecedence);
|
||||
var operand = ParseSubExpression(options, newPrecedence);
|
||||
lhs = Factory.UnaryPrefixOperationExpression(Factory.Token(operation), operand);
|
||||
}
|
||||
else
|
||||
{
|
||||
lhs = ParseTerm();
|
||||
lhs = ParseTerm(options);
|
||||
}
|
||||
while (true)
|
||||
{
|
||||
@ -566,7 +582,7 @@ namespace Parser
|
||||
}
|
||||
|
||||
EatToken();
|
||||
var rhs = ParseSubExpression(newPrecedence);
|
||||
var rhs = ParseSubExpression(options, newPrecedence);
|
||||
if (rhs == null && token.Kind == TokenKind.Colon) // for parsing things like a{:}
|
||||
{
|
||||
rhs = Factory.EmptyExpression();
|
||||
|
@ -264,15 +264,15 @@ namespace Parser
|
||||
public CellArrayElementAccessExpressionNode CellArrayElementAccessExpression(
|
||||
ExpressionNode cellArray,
|
||||
TokenNode openingBrace,
|
||||
ExpressionNode index,
|
||||
ArrayElementListNode indices,
|
||||
TokenNode closingBrace)
|
||||
{
|
||||
var children = new List<SyntaxNode> {cellArray, openingBrace, index, closingBrace};
|
||||
var children = new List<SyntaxNode> {cellArray, openingBrace, indices, closingBrace};
|
||||
var result = new CellArrayElementAccessExpressionNode(
|
||||
children,
|
||||
cellArray,
|
||||
openingBrace,
|
||||
index,
|
||||
indices,
|
||||
closingBrace);
|
||||
SetParent(result);
|
||||
return result;
|
||||
|
@ -340,19 +340,19 @@ namespace Parser
|
||||
{
|
||||
public ExpressionNode CellArray { get; }
|
||||
public TokenNode OpeningBrace { get; }
|
||||
public ExpressionNode Index { get; }
|
||||
public ArrayElementListNode Indices { get; }
|
||||
public TokenNode ClosingBrace { get; }
|
||||
|
||||
public CellArrayElementAccessExpressionNode(
|
||||
List<SyntaxNode> children,
|
||||
ExpressionNode cellArray,
|
||||
TokenNode openingBrace,
|
||||
ExpressionNode index,
|
||||
ArrayElementListNode indices,
|
||||
TokenNode closingBrace) : base(children)
|
||||
{
|
||||
CellArray = cellArray;
|
||||
OpeningBrace = openingBrace;
|
||||
Index = index;
|
||||
Indices = indices;
|
||||
ClosingBrace = closingBrace;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user