using System.Collections.Generic; using System.Linq; using Lexer; using NUnit.Framework; namespace Parser.Tests { public class MParserShould { private static MParser CreateParser(string text) { var window = new TextWindowWithNull(text); var lexer = new MLexer(window, new PureTokenFactory(window)); var tokens = lexer.ParseAll(); var parser = new MParser(tokens); return parser; } [Test] public void ParseAssignmentExpression() { var text = "a = b"; var sut = CreateParser(text); var actual = sut.ParseExpression(); Assert.IsInstanceOf(actual); Assert.AreEqual(text, actual.FullText); } [Test] public void ParseSimpleStatement() { var text = "a = b"; var sut = CreateParser(text); var actual = sut.ParseStatement(); Assert.IsInstanceOf(actual); Assert.AreEqual(text, actual.FullText); } [Test] public void ParseFunctionCallExpression() { var text = "func(a, 2, 'abc', d)"; var sut = CreateParser(text); var actual = sut.ParseExpression(); Assert.IsInstanceOf(actual); var f = actual as FunctionCallExpressionNode; Assert.AreEqual(4, f?.Parameters.Parameters.Count); Assert.AreEqual(text, actual.FullText); } [Test] public void ParseArrayLiteralExpression() { var text = "[a, 2, 'text']"; var sut = CreateParser(text); var actual = sut.ParseExpression(); Assert.IsInstanceOf(actual); var a = actual as ArrayLiteralExpressionNode; Assert.AreEqual(3, a?.Elements.Elements.Count); Assert.AreEqual(text, actual.FullText); } [Test] public void ParseLeftAssociativeSamePrecedence() { var text = "2 + 3 + 4"; var sut = CreateParser(text); var actual = sut.ParseExpression(); Assert.IsInstanceOf(actual); var e = (BinaryOperationExpressionNode)actual; Assert.IsInstanceOf(e.Lhs); Assert.IsInstanceOf(e.Rhs); Assert.AreEqual(text, actual.FullText); } [Test] public void ParseLeftAssociativeRaisingPrecedence() { var text = "2 + 3 * 4"; var sut = CreateParser(text); var actual = sut.ParseExpression(); Assert.IsInstanceOf(actual); var e = (BinaryOperationExpressionNode) actual; Assert.AreEqual(TokenKind.Plus, e.Operation.Token.Kind); Assert.IsInstanceOf(e.Lhs); Assert.IsInstanceOf(e.Rhs); Assert.AreEqual(text, actual.FullText); } [Test] public void ParseLeftAssociativeLoweringPrecedence() { var text = "2 * 3 + 4"; var sut = CreateParser(text); var actual = sut.ParseExpression(); Assert.IsInstanceOf(actual); var e = (BinaryOperationExpressionNode) actual; Assert.AreEqual(TokenKind.Plus, e.Operation.Token.Kind); Assert.IsInstanceOf(e.Lhs); Assert.IsInstanceOf(e.Rhs); Assert.AreEqual(text, actual.FullText); } [Test] public void ParseUnaryOperators() { var text = "-42"; var sut = CreateParser(text); var actual = sut.ParseExpression(); Assert.IsInstanceOf(actual); var e = (UnaryPrefixOperationExpressionNode) actual; Assert.AreEqual(TokenKind.Minus, e.Operation.Token.Kind); Assert.IsInstanceOf(e.Operand); Assert.AreEqual(text, actual.FullText); } [Test] public void ParseMemberAccess() { var text = "a.b.c"; var sut = CreateParser(text); var actual = sut.ParseExpression(); Assert.IsInstanceOf(actual); var m = (MemberAccessNode) actual; Assert.IsInstanceOf(m.LeftOperand); Assert.IsInstanceOf(m.RightOperand); Assert.AreEqual(text, actual.FullText); } [Test] public void ParseWhileStatement() { var text = "while a < b c = d end"; var sut = CreateParser(text); var actual = sut.ParseStatement(); Assert.IsInstanceOf(actual); Assert.AreEqual(text, actual.FullText); } [Test] public void ParseWhileStatementWithComma() { var text = "while a < b, c = d end"; var sut = CreateParser(text); var actual = sut.ParseStatement(); Assert.IsInstanceOf(actual); Assert.AreEqual(text, actual.FullText); } [Test] public void ParseIfStatement() { var text = "if 2 < 3 a = b end"; var sut = CreateParser(text); var actual = sut.ParseStatement(); Assert.IsInstanceOf(actual); Assert.AreEqual(text, actual.FullText); } [Test] public void ParseIfElseStatement() { var text = "if 2 < 3 a = b else c = d end"; var sut = CreateParser(text); var actual = sut.ParseStatement(); Assert.IsInstanceOf(actual); Assert.AreEqual(text, actual.FullText); } [Test] public void ParseParenthesizedExpression() { var text = "2 * (3 + 4)"; var sut = CreateParser(text); var actual = sut.ParseExpression(); Assert.IsInstanceOf(actual); var e = (BinaryOperationExpressionNode) actual; Assert.IsInstanceOf(e.Lhs); Assert.IsInstanceOf(e.Rhs); var p = (ParenthesizedExpressionNode) e.Rhs; Assert.IsInstanceOf(p.Expression); Assert.AreEqual(text, actual.FullText); } [Test] public void ParseForStatement() { var text = "for i = 1:5 a = i end"; var sut = CreateParser(text); var actual = sut.ParseStatement(); Assert.IsInstanceOf(actual); Assert.AreEqual(text, actual.FullText); } [Test] public void ParseEmptyArray() { var text = "[]"; var sut = CreateParser(text); var actual = sut.ParseExpression(); Assert.IsInstanceOf(actual); var a = (ArrayLiteralExpressionNode) actual; Assert.AreEqual(0, a.Elements.Elements.Count); Assert.AreEqual(text, actual.FullText); } [Test] public void ParseCellArrayLiteral() { var text = "{ 1 2, 3 }"; var sut = CreateParser(text); var actual = sut.ParseExpression(); Assert.IsInstanceOf(actual); var a = (CellArrayLiteralExpressionNode) actual; Assert.AreEqual(3, a.Elements.Elements.Count); Assert.AreEqual(text, actual.FullText); } [Test] public void ParseIndirectMemberAccess() { var text = "abc.(def)"; var sut = CreateParser(text); var actual = sut.ParseExpression(); Assert.IsInstanceOf(actual); var a = (MemberAccessNode) actual; Assert.IsInstanceOf(a.LeftOperand); Assert.IsInstanceOf(a.RightOperand); Assert.AreEqual(text, actual.FullText); } [Test] public void ParseMemberAccessAfterElementAccess() { var text = "a(1).b"; var sut = CreateParser(text); var actual = sut.ParseExpression(); Assert.IsInstanceOf(actual); var m = (MemberAccessNode) actual; Assert.IsInstanceOf(m.LeftOperand); Assert.IsInstanceOf(m.RightOperand); Assert.AreEqual(text, actual.FullText); } [Test] public void ParseFunctionDeclarationWithoutInputs() { var text = "function a = b a = 1"; var sut = CreateParser(text); var actual = sut.ParseStatement(); Assert.IsInstanceOf(actual); var f = (FunctionDeclarationNode) actual; 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(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(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(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(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(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(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(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(actual); var a = (ArrayLiteralExpressionNode) actual; Assert.AreEqual(3, a.Elements.Elements.Count); Assert.AreEqual(text, actual.FullText); } [Test] public void ParseFunctionHandle() { var text = "@sqrt"; var sut = CreateParser(text); var actual = sut.ParseExpression(); Assert.IsInstanceOf(actual); var f = (NamedFunctionHandleNode) actual; Assert.AreEqual(1, f.FunctionName.Names.Count); Assert.AreEqual("sqrt", f.FunctionName.Names[0].Token.PureToken.LiteralText); Assert.AreEqual(text, actual.FullText); } [Test] public void ParseFunctionHandleWithCompoundName() { var text = "@a.b.c"; var sut = CreateParser(text); var actual = sut.ParseExpression(); Assert.IsInstanceOf(actual); var f = (NamedFunctionHandleNode) actual; Assert.AreEqual(3, f.FunctionName.Names.Count); Assert.AreEqual(text, actual.FullText); } [Test] public void ParseLambda() { var text = "@(x, y) x + y"; var sut = CreateParser(text); var actual = sut.ParseExpression(); Assert.IsInstanceOf(actual); var f = (LambdaNode) actual; Assert.AreEqual(2, f.Input.Parameters.Parameters.Count); Assert.IsInstanceOf(f.Body); Assert.AreEqual(text, actual.FullText); } [Test] public void ParseTildeAsResultReplacement() { var text = "[a, ~, b]"; var sut = CreateParser(text); var actual = sut.ParseExpression(); Assert.IsInstanceOf(actual); var f = (ArrayLiteralExpressionNode) actual; Assert.AreEqual(3, f.Elements.Elements.Count); Assert.IsInstanceOf(f.Elements.Elements[1]); Assert.AreEqual(text, actual.FullText); } [Test] public void ParseTildeAsFunctionInputReplacement() { var text = "function a(b, ~, c) end"; var sut = CreateParser(text); var actual = sut.ParseStatement(); Assert.IsInstanceOf(actual); var f = (FunctionDeclarationNode) actual; Assert.AreEqual(3, f.InputDescription.Parameters.Parameters.Count); CollectionAssert.AreEqual(new[] { "b", "~", "c" }, f.InputDescription.Parameters.Parameters.Select(p => (p as TokenNode).Token.PureToken.LiteralText)); Assert.AreEqual(text, actual.FullText); } [Test] public void ParseDotTranspose() { var text = "a.'"; var sut = CreateParser(text); var actual = sut.ParseExpression(); Assert.IsInstanceOf(actual); var e = (UnaryPostfixOperationExpressionNode) actual; Assert.AreEqual(TokenKind.DotTranspose, e.Operation.Token.Kind); Assert.AreEqual("a", (e.Operand as IdentifierNameNode)?.Token.PureToken.LiteralText); Assert.AreEqual(text, actual.FullText); } } }