package org.shedlang.compiler.parser; import org.junit.jupiter.api.Test; import org.shedlang.compiler.tokeniser.UnexpectedTokenException; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.shedlang.compiler.ast.untyped.UntypedNodeMatchers.*; import static org.shedlang.compiler.parser.ParserTesting.parseString; import static org.zwobble.precisely.AssertThat.assertThat; import static org.zwobble.precisely.Matchers.*; public class ParserFunctionExpressionTests { @Test public void canParseMinimalFunction() { var source = """ fn () -> Unit { }"""; var node = parseString(source, Parser::parseTopLevelExpression); assertThat( node, isUntypedFunctionExpressionNode() .withSignature( isUntypedFunctionSignatureNode() .withParams(isUntypedParamsNode(isSequence(), isSequence())) .withEffect(isOptionalEmpty()) .withReturnType(isUntypedTypeLevelReferenceNode("Unit")) ) .withBody(isUntypedBlockNode(isSequence())) ); } @Test public void canParseFunctionWithBodyWithoutReturn() { var source = """ fn () -> Unit { a; b; c; }"""; var node = parseString(source, Parser::parseTopLevelExpression); assertThat( node, isUntypedFunctionExpressionNode() .withBody(isUntypedBlockNode(isSequence( isUntypedExpressionStatementNode(isUntypedReferenceNode("a")), isUntypedExpressionStatementNode(isUntypedReferenceNode("b")), isUntypedExpressionStatementNode(isUntypedReferenceNode("c")) ))) ); } @Test public void canParseFunctionWithBodyWithBlockReturn() { var source = """ fn () -> Unit { a; b; c }"""; var node = parseString(source, Parser::parseTopLevelExpression); assertThat( node, isUntypedFunctionExpressionNode() .withBody(isUntypedBlockNode(isSequence( isUntypedExpressionStatementNode(isUntypedReferenceNode("a")), isUntypedExpressionStatementNode(isUntypedReferenceNode("b")), isUntypedBlockReturnNode(isUntypedReferenceNode("c")) ))) ); } @Test public void blockReturnEndsFunction() { var source = """ fn () -> Unit { a; b c }"""; var error = assertThrows( UnexpectedTokenException.class, () -> parseString(source, Parser::parseTopLevelExpression) ); assertThat(error.getActual().value().toString(), equalTo("c")); assertThat(error.getExpected(), equalTo(TokenType.SYMBOL_BRACE_CLOSE.toString())); } }