From d359527cf83981a63d0e56b869ac85cd60256548 Mon Sep 17 00:00:00 2001 From: Alexander Luzgarev Date: Sun, 1 Apr 2018 19:24:46 +0200 Subject: [PATCH] Parse lambda expressions --- Parser.Tests/MParserShould.cs | 18 ++++++++++++++++-- Parser/MParser.cs | 17 +++++++++++++---- Parser/SyntaxFactory.cs | 23 +++++++++++++++++++++-- Parser/SyntaxNode.cs | 28 ++++++++++++++++++++++++++-- 4 files changed, 76 insertions(+), 10 deletions(-) diff --git a/Parser.Tests/MParserShould.cs b/Parser.Tests/MParserShould.cs index ff46ebd..f04d4c7 100644 --- a/Parser.Tests/MParserShould.cs +++ b/Parser.Tests/MParserShould.cs @@ -356,9 +356,23 @@ namespace Parser.Tests var text = "@sqrt"; var sut = CreateParser(text); var actual = sut.ParseExpression(); - Assert.IsInstanceOf(actual); - var f = (FunctionHandleNode) actual; + Assert.IsInstanceOf(actual); + var f = (NamedFunctionHandleNode) actual; Assert.AreEqual("sqrt", f.IdentifierName.Token.PureToken.LiteralText); + 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); } } } \ No newline at end of file diff --git a/Parser/MParser.cs b/Parser/MParser.cs index e2d1f92..98dd394 100644 --- a/Parser/MParser.cs +++ b/Parser/MParser.cs @@ -553,10 +553,19 @@ namespace Parser private FunctionHandleNode ParseFunctionHandle() { var atSign = EatToken(); - var identifierName = EatToken(TokenKind.Identifier); - return Factory.FunctionHandle( - Factory.Token(atSign), - Factory.IdentifierName(identifierName)); + if (CurrentToken.Kind == TokenKind.Identifier) + { + var identifierName = EatToken(TokenKind.Identifier); + return Factory.NamedFunctionHandle( + Factory.Token(atSign), + Factory.IdentifierName(identifierName)); + } else if (CurrentToken.Kind == TokenKind.OpeningBracket) + { + var inputs = ParseFunctionInputDescription(); + var body = ParseExpression(); + return Factory.Lambda(Factory.Token(atSign), inputs, body); + } + throw new ParsingException($"Unexpected token {CurrentToken.PureToken} while parsing function handle at {CurrentToken.PureToken.Position}."); } private ExpressionNode ParseSubExpression(ParseOptions options, Precedence precedence) diff --git a/Parser/SyntaxFactory.cs b/Parser/SyntaxFactory.cs index 933b812..571d9be 100644 --- a/Parser/SyntaxFactory.cs +++ b/Parser/SyntaxFactory.cs @@ -542,7 +542,7 @@ namespace Parser return result; } - public FunctionHandleNode FunctionHandle( + public NamedFunctionHandleNode NamedFunctionHandle( TokenNode atSign, IdentifierNameNode identifierName) { @@ -551,7 +551,7 @@ namespace Parser atSign, identifierName }; - var result = new FunctionHandleNode( + var result = new NamedFunctionHandleNode( children, atSign, identifierName); @@ -559,5 +559,24 @@ namespace Parser return result; } + public LambdaNode Lambda( + TokenNode atSign, + FunctionInputDescriptionNode input, + ExpressionNode body) + { + var children = new List + { + atSign, + input, + body + }; + var result = new LambdaNode( + children, + atSign, + input, + body); + SetParent(result); + return result; + } } } \ No newline at end of file diff --git a/Parser/SyntaxNode.cs b/Parser/SyntaxNode.cs index 2859ad7..cf1dd7c 100644 --- a/Parser/SyntaxNode.cs +++ b/Parser/SyntaxNode.cs @@ -587,12 +587,20 @@ namespace Parser } } - public class FunctionHandleNode : ExpressionNode + public abstract class FunctionHandleNode : ExpressionNode + { + protected FunctionHandleNode( + List children) : base(children) + { + } + } + + public class NamedFunctionHandleNode : FunctionHandleNode { public TokenNode AtSign { get; } public IdentifierNameNode IdentifierName { get; } - public FunctionHandleNode( + public NamedFunctionHandleNode( List children, TokenNode atSign, IdentifierNameNode identifierName) : base(children) @@ -602,5 +610,21 @@ namespace Parser } } + public class LambdaNode : FunctionHandleNode + { + public TokenNode AtSign { get; } + public FunctionInputDescriptionNode Input { get; } + public ExpressionNode Body { get; } + public LambdaNode( + List children, + TokenNode atSign, + FunctionInputDescriptionNode input, + ExpressionNode body) : base(children) + { + AtSign = atSign; + Input = input; + Body = body; + } + } } \ No newline at end of file