From 1886fc2b214bb2c5bfc4cb1ca3d49975c76da0d6 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Sat, 23 Dec 2023 12:05:34 +0000 Subject: Parse constructed types --- .../ast/untyped/UntypedConstructedTypeNode.java | 12 +++ .../untyped/UntypedTypeLevelExpressionNode.java | 2 +- .../shedlang/compiler/parser/OperationParser.java | 7 +- .../java/org/shedlang/compiler/parser/Parser.java | 111 +++++++++++++++++---- .../parser/TypeLevelOperatorPrecedence.java | 15 +++ .../shedlang/compiler/typechecker/TypeChecker.java | 3 + 6 files changed, 128 insertions(+), 22 deletions(-) create mode 100644 src/main/java/org/shedlang/compiler/ast/untyped/UntypedConstructedTypeNode.java create mode 100644 src/main/java/org/shedlang/compiler/parser/TypeLevelOperatorPrecedence.java (limited to 'src/main/java') diff --git a/src/main/java/org/shedlang/compiler/ast/untyped/UntypedConstructedTypeNode.java b/src/main/java/org/shedlang/compiler/ast/untyped/UntypedConstructedTypeNode.java new file mode 100644 index 00000000..48cb1bf6 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/ast/untyped/UntypedConstructedTypeNode.java @@ -0,0 +1,12 @@ +package org.shedlang.compiler.ast.untyped; + +import org.shedlang.compiler.sources.Source; + +import java.util.List; + +public record UntypedConstructedTypeNode( + UntypedTypeLevelExpressionNode receiver, + List args, + Source source +) implements UntypedTypeLevelExpressionNode { +} 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 5af90cfa..7f677119 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 UntypedFunctionTypeNode, UntypedTupleTypeNode, UntypedTypeLevelReferenceNode { +public sealed interface UntypedTypeLevelExpressionNode extends UntypedNode permits UntypedConstructedTypeNode, UntypedFunctionTypeNode, UntypedTupleTypeNode, UntypedTypeLevelReferenceNode { } diff --git a/src/main/java/org/shedlang/compiler/parser/OperationParser.java b/src/main/java/org/shedlang/compiler/parser/OperationParser.java index 6f3e170e..9a4a25ea 100644 --- a/src/main/java/org/shedlang/compiler/parser/OperationParser.java +++ b/src/main/java/org/shedlang/compiler/parser/OperationParser.java @@ -1,12 +1,11 @@ package org.shedlang.compiler.parser; -import org.shedlang.compiler.ast.untyped.UntypedExpressionNode; import org.shedlang.compiler.tokeniser.TokenIterator; import java.util.stream.Stream; -public interface OperationParser { - OperatorPrecedence precedence(); +public interface OperationParser { + TOperatorPrecedence precedence(); Stream operatorTokenTypes(); - UntypedExpressionNode parse(UntypedExpressionNode left, TokenIterator tokens); + TUntypedExpressionNode parse(TUntypedExpressionNode left, TokenIterator tokens); } diff --git a/src/main/java/org/shedlang/compiler/parser/Parser.java b/src/main/java/org/shedlang/compiler/parser/Parser.java index 753a6d75..3c91c561 100644 --- a/src/main/java/org/shedlang/compiler/parser/Parser.java +++ b/src/main/java/org/shedlang/compiler/parser/Parser.java @@ -24,7 +24,10 @@ public class Parser { private Parser() { } - private static class BinaryOperationParser implements OperationParser { + private static class BinaryOperationParser implements OperationParser< + OperatorPrecedence, + UntypedExpressionNode + > { private final TokenType operatorTokenType; private final OperatorPrecedence precedence; private final UntypedBinaryOperator operator; @@ -188,7 +191,10 @@ public class Parser { return new UntypedBreakNode(expression, source); } - private static class CallParser implements OperationParser { + private static class CallParser implements OperationParser< + OperatorPrecedence, + UntypedExpressionNode + > { @Override public OperatorPrecedence precedence() { return OperatorPrecedence.CALL; @@ -216,6 +222,39 @@ public class Parser { } } + private static class ConstructedTypeParser implements OperationParser< + TypeLevelOperatorPrecedence, + UntypedTypeLevelExpressionNode + > { + @Override + public TypeLevelOperatorPrecedence precedence() { + return TypeLevelOperatorPrecedence.CONSTRUCTED_TYPE; + } + + @Override + public Stream operatorTokenTypes() { + return Stream.of(TokenType.SYMBOL_SQUARE_OPEN); + } + + @Override + public UntypedTypeLevelExpressionNode parse(UntypedTypeLevelExpressionNode left, TokenIterator tokens) { + var start = left.source().start(); + + tokens.skip(TokenType.SYMBOL_SQUARE_OPEN); + var args = parseMany( + () -> tokens.isNext(TokenType.SYMBOL_SQUARE_CLOSE), + () -> parseTopLevelTypeLevelExpression(tokens), + () -> tokens.trySkip(TokenType.SYMBOL_COMMA) + ); + tokens.skip(TokenType.SYMBOL_SQUARE_CLOSE); + + var end = tokens.position(); + var source = start.to(end); + + return new UntypedConstructedTypeNode(left, args, source); + } + } + private static UntypedEffectDefinitionNode parseEffectDefinition( TokenIterator tokens ) { @@ -281,7 +320,7 @@ public class Parser { return new UntypedFunctionTypeNode(params, Optional.empty(), returnType, source); } - private static final Map OPERATION_PARSERS = Stream.of( + private static final Map> OPERATION_PARSERS = Stream.of( new FieldAccessParser(), new BinaryOperationParser(TokenType.SYMBOL_EQUALS_EQUALS, OperatorPrecedence.EQUALS, UntypedBinaryOperator.EQUALS), new BinaryOperationParser(TokenType.SYMBOL_BANG_EQUALS, OperatorPrecedence.EQUALS, UntypedBinaryOperator.NOT_EQUAL), @@ -354,7 +393,10 @@ public class Parser { ); } - private static class FieldAccessParser implements OperationParser { + private static class FieldAccessParser implements OperationParser< + OperatorPrecedence, + UntypedExpressionNode + > { @Override public OperatorPrecedence precedence() { return OperatorPrecedence.CALL; @@ -848,6 +890,22 @@ public class Parser { }; } + static UntypedTypeLevelExpressionNode parsePrimaryTypeLevelExpression(TokenIterator tokens) { + return switch (tokens.peek().tokenType()) { + case IDENTIFIER -> + parseTypeLevelReference(tokens); + + case KEYWORD_FN -> + parseFunctionType(tokens); + + case SYMBOL_HASH_PAREN_OPEN -> + parseTupleType(tokens); + + default -> + throw new UnexpectedTokenException("type-level expression", tokens.peek()); + }; + } + private static UntypedFunctionStatementNode parseResume(TokenIterator tokens) { var start = tokens.position(); @@ -996,19 +1054,7 @@ public class Parser { } static UntypedTypeLevelExpressionNode parseTopLevelTypeLevelExpression(TokenIterator tokens) { - return switch (tokens.peek().tokenType()) { - case IDENTIFIER -> - parseTypeLevelReference(tokens); - - case KEYWORD_FN -> - parseFunctionType(tokens); - - case SYMBOL_HASH_PAREN_OPEN -> - parseTupleType(tokens); - - default -> - throw new UnexpectedTokenException("type-level expression", tokens.peek()); - }; + return parseTypeLevelExpression(tokens, Optional.empty()); } public static UntypedNamespaceNode parseNamespace( @@ -1212,6 +1258,37 @@ public class Parser { return new UntypedTupleTypeNode(elements, source); } + private static final Map> TYPE_LEVEL_OPERATION_PARSERS = Stream.of( + new ConstructedTypeParser() + ) + .flatMap(parser -> + parser.operatorTokenTypes().map(tokenType -> Map.entry(tokenType, parser)) + ) + .collect(Collectors.toMap( + x -> x.getKey(), + x -> x.getValue() + )); + + private static UntypedTypeLevelExpressionNode parseTypeLevelExpression( + TokenIterator tokens, + Optional parentPrecedence + ) { + var left = parsePrimaryTypeLevelExpression(tokens); + + while (true) { + var operationParser = TYPE_LEVEL_OPERATION_PARSERS.get(tokens.peek().tokenType()); + if ( + operationParser == null || ( + parentPrecedence.isPresent() && + operationParser.precedence().precedence() <= parentPrecedence.get().precedence() + ) + ) { + return left; + } + left = operationParser.parse(left, tokens); + } + } + private static Optional> parseTypeLevelParamsOptional( TokenIterator tokens ) { diff --git a/src/main/java/org/shedlang/compiler/parser/TypeLevelOperatorPrecedence.java b/src/main/java/org/shedlang/compiler/parser/TypeLevelOperatorPrecedence.java new file mode 100644 index 00000000..2068b2ad --- /dev/null +++ b/src/main/java/org/shedlang/compiler/parser/TypeLevelOperatorPrecedence.java @@ -0,0 +1,15 @@ +package org.shedlang.compiler.parser; + +public enum TypeLevelOperatorPrecedence { + CONSTRUCTED_TYPE(1); + + private final int precedence; + + TypeLevelOperatorPrecedence(int precedence) { + this.precedence = precedence; + } + + public int precedence() { + return precedence; + } +} diff --git a/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java b/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java index f083913f..b789e888 100644 --- a/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java +++ b/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java @@ -1528,6 +1528,9 @@ public class TypeChecker { TypeCheckerContext context ) { return switch (untyped) { + case UntypedConstructedTypeNode constructedType -> + throw new UnsupportedOperationException("TODO"); + case UntypedFunctionTypeNode functionType -> { var typedFunctionTypeNode = typeCheckFunctionType(functionType, context); -- cgit v1.2.3