From fa6b2a24aad096824790501550623a7c3c2418c1 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Sat, 30 Sep 2023 10:28:05 +0100 Subject: Parse sum types --- .../ast/untyped/UntypedSumTypeDefinitionNode.java | 4 +- .../java/org/shedlang/compiler/parser/Parser.java | 53 ++++++++++++++++++++++ .../org/shedlang/compiler/parser/TokenType.java | 1 + .../org/shedlang/compiler/parser/Tokeniser.java | 1 + 4 files changed, 58 insertions(+), 1 deletion(-) (limited to 'src/main/java') diff --git a/src/main/java/org/shedlang/compiler/ast/untyped/UntypedSumTypeDefinitionNode.java b/src/main/java/org/shedlang/compiler/ast/untyped/UntypedSumTypeDefinitionNode.java index 3a49f46e..681c4506 100644 --- a/src/main/java/org/shedlang/compiler/ast/untyped/UntypedSumTypeDefinitionNode.java +++ b/src/main/java/org/shedlang/compiler/ast/untyped/UntypedSumTypeDefinitionNode.java @@ -2,9 +2,11 @@ package org.shedlang.compiler.ast.untyped; import org.shedlang.compiler.sources.Source; +import java.util.List; + public record UntypedSumTypeDefinitionNode( String name, - UntypedTypeLevelExpressionNode variants, + List variants, Source source ) implements UntypedNamespaceStatementNode { } diff --git a/src/main/java/org/shedlang/compiler/parser/Parser.java b/src/main/java/org/shedlang/compiler/parser/Parser.java index e3c78d07..84900688 100644 --- a/src/main/java/org/shedlang/compiler/parser/Parser.java +++ b/src/main/java/org/shedlang/compiler/parser/Parser.java @@ -429,6 +429,13 @@ public class Parser { return new UntypedIntLiteralNode(value, source); } + /** + * Parse zero, one, or many instances of {@code T} using {@code parseOne}. + * Each instance is expected to be separated by tokens consumed by + * {@code parseSeparator}. Parsing stops either if {@code parseSeparator} + * returns false, or if {@code stop} returns false. Trailing separators + * are permitted. + */ private static List parseMany( BooleanSupplier stop, Supplier parseOne, @@ -447,6 +454,27 @@ public class Parser { return values; } + /** + * Parse one or more instances of {@code T} using {@code parseOne}. Each + * instance is expected to be separated by tokens consumed by + * {@code parseSeparator}. Parsing stops if {@code parseSeparator} returns + * false. Trailing separators are not permitted. + */ + private static List parseOneOrMoreNoTrailingSeparator( + Supplier parseOne, + BooleanSupplier parseSeparator + ) { + var values = new ArrayList(); + + while (true) { + var value = parseOne.get(); + values.add(value); + if (!parseSeparator.getAsBoolean()) { + return values; + } + } + } + static UntypedNamespaceStatementNode parseNamespaceStatement(TokenIterator tokens) { return switch (tokens.peek().tokenType()) { case KEYWORD_FUN -> @@ -455,6 +483,9 @@ public class Parser { case KEYWORD_STRUCT -> parseStructDefinition(tokens); + case KEYWORD_SUMTYPE -> + parseSumTypeDefinition(tokens); + case KEYWORD_VAL -> parseAssign(tokens); @@ -603,6 +634,28 @@ public class Parser { return parseExpression(tokens, Optional.of(parentPrecedence)); } + private static UntypedNamespaceStatementNode parseSumTypeDefinition(TokenIterator tokens) { + var start = tokens.position(); + + tokens.skip(TokenType.KEYWORD_SUMTYPE); + + var name = tokens.nextValue(TokenType.IDENTIFIER); + + tokens.skip(TokenType.SYMBOL_EQUALS); + + var variants = parseOneOrMoreNoTrailingSeparator( + () -> parseTopLevelTypeLevelExpression(tokens), + () -> tokens.trySkip(TokenType.SYMBOL_BAR) + ); + + tokens.skip(TokenType.SYMBOL_SEMICOLON); + + var end = tokens.position(); + var source = start.to(end); + + return new UntypedSumTypeDefinitionNode(name, variants, source); + } + static UntypedExpressionNode parseTopLevelExpression(TokenIterator tokens) { return parseExpression(tokens, Optional.empty()); } diff --git a/src/main/java/org/shedlang/compiler/parser/TokenType.java b/src/main/java/org/shedlang/compiler/parser/TokenType.java index ec4fd332..9c8183dc 100644 --- a/src/main/java/org/shedlang/compiler/parser/TokenType.java +++ b/src/main/java/org/shedlang/compiler/parser/TokenType.java @@ -24,6 +24,7 @@ public enum TokenType { SYMBOL_BANG, SYMBOL_BANG_EQUALS, + SYMBOL_BAR, SYMBOL_BRACE_OPEN, SYMBOL_BRACE_CLOSE, SYMBOL_COLON, diff --git a/src/main/java/org/shedlang/compiler/parser/Tokeniser.java b/src/main/java/org/shedlang/compiler/parser/Tokeniser.java index f33e4d53..7659d717 100644 --- a/src/main/java/org/shedlang/compiler/parser/Tokeniser.java +++ b/src/main/java/org/shedlang/compiler/parser/Tokeniser.java @@ -43,6 +43,7 @@ public class Tokeniser { RegexTokeniser.rule(TokenType.SYMBOL_HASH_PAREN_OPEN, "#\\("), RegexTokeniser.rule(TokenType.SYMBOL_BANG, "!"), + RegexTokeniser.rule(TokenType.SYMBOL_BAR, "\\|"), RegexTokeniser.rule(TokenType.SYMBOL_BRACE_OPEN, "\\{"), RegexTokeniser.rule(TokenType.SYMBOL_BRACE_CLOSE, "\\}"), RegexTokeniser.rule(TokenType.SYMBOL_COLON, ":"), -- cgit v1.2.3