aboutsummaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2023-09-30 10:28:05 +0100
committerMichael Williamson <mike@zwobble.org>2023-09-30 10:28:05 +0100
commitfa6b2a24aad096824790501550623a7c3c2418c1 (patch)
tree126d85c6f62130ce53fb3d950ac94398e2139c84 /src/main/java
parent5c64771c085d2064c79bcd212f513f5a211146eb (diff)
Parse sum types
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/org/shedlang/compiler/ast/untyped/UntypedSumTypeDefinitionNode.java4
-rw-r--r--src/main/java/org/shedlang/compiler/parser/Parser.java53
-rw-r--r--src/main/java/org/shedlang/compiler/parser/TokenType.java1
-rw-r--r--src/main/java/org/shedlang/compiler/parser/Tokeniser.java1
4 files changed, 58 insertions, 1 deletions
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<UntypedTypeLevelExpressionNode> 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 <T> List<T> parseMany(
BooleanSupplier stop,
Supplier<T> 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 <T> List<T> parseOneOrMoreNoTrailingSeparator(
+ Supplier<T> parseOne,
+ BooleanSupplier parseSeparator
+ ) {
+ var values = new ArrayList<T>();
+
+ while (true) {
+ var value = parseOne.get();
+ values.add(value);
+ if (!parseSeparator.getAsBoolean()) {
+ return values;
+ }
+ }
+ }
+
static UntypedNamespaceStatementNode parseNamespaceStatement(TokenIterator<TokenType> 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<TokenType> 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<TokenType> 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, ":"),