diff options
| author | Michael Williamson <mike@zwobble.org> | 2023-10-22 22:23:01 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2023-10-22 22:23:01 +0100 |
| commit | d1d0984bc8a157a2f001d3c991dae5c9498cd790 (patch) | |
| tree | 89056dc50059c60c4ce1bf9aa18a8045fb282036 /src/main/java | |
| parent | bc94a020433c8b7dc0adaa2a6adf235da9c9b4e9 (diff) | |
Parse function types
Diffstat (limited to 'src/main/java')
5 files changed, 113 insertions, 9 deletions
diff --git a/src/main/java/org/shedlang/compiler/ast/untyped/UntypedFunctionTypeNode.java b/src/main/java/org/shedlang/compiler/ast/untyped/UntypedFunctionTypeNode.java new file mode 100644 index 00000000..6d4d9502 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/ast/untyped/UntypedFunctionTypeNode.java @@ -0,0 +1,13 @@ +package org.shedlang.compiler.ast.untyped; + +import org.shedlang.compiler.sources.Source; + +import java.util.Optional; + +public record UntypedFunctionTypeNode( + UntypedParamTypesNode params, + Optional<UntypedTypeLevelExpressionNode> effect, + UntypedTypeLevelExpressionNode returnType, + Source source +) implements UntypedTypeLevelExpressionNode { +} diff --git a/src/main/java/org/shedlang/compiler/ast/untyped/UntypedParamTypesNode.java b/src/main/java/org/shedlang/compiler/ast/untyped/UntypedParamTypesNode.java new file mode 100644 index 00000000..60fa66c3 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/ast/untyped/UntypedParamTypesNode.java @@ -0,0 +1,12 @@ +package org.shedlang.compiler.ast.untyped; + +import org.shedlang.compiler.sources.Source; + +import java.util.List; + +public record UntypedParamTypesNode( + List<UntypedTypeLevelExpressionNode> positional, + List<UntypedParamNode> named, + Source source +) implements UntypedNode { +} diff --git a/src/main/java/org/shedlang/compiler/ast/untyped/UntypedTypeLevelExpressionNode.java b/src/main/java/org/shedlang/compiler/ast/untyped/UntypedTypeLevelExpressionNode.java index fdbc5320..5af90cfa 100644 --- a/src/main/java/org/shedlang/compiler/ast/untyped/UntypedTypeLevelExpressionNode.java +++ b/src/main/java/org/shedlang/compiler/ast/untyped/UntypedTypeLevelExpressionNode.java @@ -1,4 +1,4 @@ package org.shedlang.compiler.ast.untyped; -public sealed interface UntypedTypeLevelExpressionNode extends UntypedNode permits UntypedTupleTypeNode, UntypedTypeLevelReferenceNode { +public sealed interface UntypedTypeLevelExpressionNode extends UntypedNode permits UntypedFunctionTypeNode, UntypedTupleTypeNode, UntypedTypeLevelReferenceNode { } diff --git a/src/main/java/org/shedlang/compiler/parser/Parser.java b/src/main/java/org/shedlang/compiler/parser/Parser.java index abd5316e..763d0a01 100644 --- a/src/main/java/org/shedlang/compiler/parser/Parser.java +++ b/src/main/java/org/shedlang/compiler/parser/Parser.java @@ -289,12 +289,7 @@ public class Parser { var params = parseParams(tokens); tokens.skip(TokenType.SYMBOL_PAREN_CLOSE); - Optional<UntypedTypeLevelExpressionNode> effect; - if (tokens.trySkip(TokenType.SYMBOL_BANG)) { - effect = Optional.of(parseTopLevelTypeLevelExpression(tokens)); - } else { - effect = Optional.empty(); - } + var effect = parseFunctionTypeEffect(tokens); tokens.skip(TokenType.SYMBOL_THIN_ARROW); var returnType = parseTopLevelTypeLevelExpression(tokens); @@ -373,6 +368,42 @@ public class Parser { } } + private static UntypedTypeLevelExpressionNode parseFunctionType( + TokenIterator<TokenType> tokens + ) { + var start = tokens.position(); + + tokens.skip(TokenType.KEYWORD_FN); + + tokens.skip(TokenType.SYMBOL_PAREN_OPEN); + var params = parseParamTypes(tokens); + tokens.skip(TokenType.SYMBOL_PAREN_CLOSE); + + var effect = parseFunctionTypeEffect(tokens); + + tokens.skip(TokenType.SYMBOL_THIN_ARROW); + + var returnType = parseTopLevelTypeLevelExpression(tokens); + + var end = tokens.position(); + var source = start.to(end); + + return new UntypedFunctionTypeNode( + params, + effect, + returnType, + source + ); + } + + private static Optional<UntypedTypeLevelExpressionNode> parseFunctionTypeEffect(TokenIterator<TokenType> tokens) { + if (tokens.trySkip(TokenType.SYMBOL_BANG)) { + return Optional.of(parseTopLevelTypeLevelExpression(tokens)); + } else { + return Optional.empty(); + } + } + private static UntypedExpressionNode parseIf(TokenIterator<TokenType> tokens) { var start = tokens.position(); @@ -545,10 +576,10 @@ public class Parser { parseMany( () -> tokens.isNext(TokenType.SYMBOL_PAREN_CLOSE), () -> { - var isNamed = tokens.trySkip(TokenType.SYMBOL_DOT); - var paramStart = tokens.position(); + var isNamed = tokens.trySkip(TokenType.SYMBOL_DOT); + var name = tokens.nextValue(TokenType.IDENTIFIER); tokens.skip(TokenType.SYMBOL_COLON); var type = parseTopLevelTypeLevelExpression(tokens); @@ -572,6 +603,48 @@ public class Parser { return new UntypedParamsNode(positional, named, paramsSource); } + private static UntypedParamTypesNode parseParamTypes(TokenIterator<TokenType> tokens) { + var paramsStart = tokens.position(); + + var positional = new ArrayList<UntypedTypeLevelExpressionNode>(); + var named = new ArrayList<UntypedParamNode>(); + + parseMany( + () -> tokens.isNext(TokenType.SYMBOL_PAREN_CLOSE), + () -> { + var paramStart = tokens.position(); + + var isNamed = tokens.trySkip(TokenType.SYMBOL_DOT); + + if (isNamed) { + var name = tokens.nextValue(TokenType.IDENTIFIER); + tokens.skip(TokenType.SYMBOL_COLON); + var type = parseTopLevelTypeLevelExpression(tokens); + + var paramEnd = tokens.position(); + var paramSource = paramStart.to(paramEnd); + + named.add(new UntypedParamNode(name, type, paramSource)); + } else { + var type = parseTopLevelTypeLevelExpression(tokens); + if (!named.isEmpty()) { + throw new PositionalParamAfterNamedParamError(type.source()); + } + + positional.add(type); + } + + return null; + }, + () -> tokens.trySkip(TokenType.SYMBOL_COMMA) + ); + + var paramsEnd = tokens.position(); + var paramsSource = paramsStart.to(paramsEnd); + + return new UntypedParamTypesNode(positional, named, paramsSource); + } + private static UntypedExpressionNode parsePrimaryExpression(TokenIterator<TokenType> tokens) { return switch (tokens.peek().tokenType()) { @@ -713,6 +786,9 @@ public class Parser { case IDENTIFIER -> parseTypeLevelReference(tokens); + case KEYWORD_FN -> + parseFunctionType(tokens); + case SYMBOL_HASH_PAREN_OPEN -> parseTupleType(tokens); diff --git a/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java b/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java index b8a487e4..40647834 100644 --- a/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java +++ b/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java @@ -1013,6 +1013,9 @@ public class TypeChecker { TypeCheckerContext context ) { return switch (untyped) { + case UntypedFunctionTypeNode functionType -> + throw new UnsupportedOperationException("TODO"); + case UntypedTupleTypeNode tuple -> { var typedTupleNode = typeCheckTupleType(tuple, context); |
