diff options
Diffstat (limited to 'src')
4 files changed, 144 insertions, 2 deletions
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedSumDefinitionNode.java b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedSumDefinitionNode.java index 7969806..66acc08 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedSumDefinitionNode.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedSumDefinitionNode.java @@ -6,7 +6,7 @@ import java.util.List; public record UntypedSumDefinitionNode( String name, - List<UntypedTypeLevelExpressionNode> variants, + List<UntypedSumVariantDefinitionNode> variants, Source source ) implements UntypedNamespaceStatementNode { } diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedSumVariantDefinitionNode.java b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedSumVariantDefinitionNode.java new file mode 100644 index 0000000..91a9f0d --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedSumVariantDefinitionNode.java @@ -0,0 +1,9 @@ +package org.zwobble.hobgoblin.compiler.ast.untyped; + +import org.zwobble.hobgoblin.compiler.sources.Source; + +public record UntypedSumVariantDefinitionNode( + UntypedTypeLevelExpressionNode type, + Source source +) implements UntypedNode { +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/parser/Parser.java b/src/main/java/org/zwobble/hobgoblin/compiler/parser/Parser.java index fbf38bb..4cd35f8 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/parser/Parser.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/parser/Parser.java @@ -49,7 +49,13 @@ public class Parser { static UntypedNamespaceStatementNode parseNamespaceStatement( TokenIterator tokens ) { - return parseStructDefinition(tokens); + if (tokens.isNext(TokenType.KEYWORD_STRUCT)) { + return parseStructDefinition(tokens); + } else if (tokens.isNext(TokenType.KEYWORD_SUM)) { + return parseSumDefinition(tokens); + } else { + throw new UnsupportedOperationException("TODO"); + } } private static UntypedStructDefinitionNode parseStructDefinition( @@ -100,6 +106,51 @@ public class Parser { ); } + private static UntypedSumDefinitionNode parseSumDefinition( + TokenIterator tokens + ) { + var start = tokens.startPosition(); + + tokens.skip(TokenType.KEYWORD_SUM); + var name = tokens.next(TokenType.IDENTIFIER); + tokens.skip(TokenType.SYMBOL_BRACE_OPEN); + + var variants = parseMany( + () -> tokens.isNext(TokenType.SYMBOL_BRACE_CLOSE), + () -> parseSumVariantDefinition(tokens), + () -> true + ); + + tokens.skip(TokenType.SYMBOL_BRACE_CLOSE); + + var end = tokens.endPosition(); + var source = createSource(start, end); + + return new UntypedSumDefinitionNode( + name.charSequence().toString(), + variants, + source + ); + } + + private static UntypedSumVariantDefinitionNode parseSumVariantDefinition( + TokenIterator tokens + ) { + var start = tokens.startPosition(); + + tokens.skip(TokenType.KEYWORD_VARIANT); + var type = parseTypeLevelExpression(tokens); + tokens.skip(TokenType.SYMBOL_SEMICOLON); + + var end = tokens.endPosition(); + var source = createSource(start, end); + + return new UntypedSumVariantDefinitionNode( + type, + source + ); + } + static UntypedTypeLevelExpressionNode parseTypeLevelExpression( TokenIterator tokens ) { diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserSumDefinitionTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserSumDefinitionTests.java new file mode 100644 index 0000000..825511e --- /dev/null +++ b/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserSumDefinitionTests.java @@ -0,0 +1,82 @@ +package org.zwobble.hobgoblin.compiler.parser; + +import org.junit.jupiter.api.Test; +import org.zwobble.hobgoblin.compiler.ast.untyped.UntypedSumDefinitionNode; +import org.zwobble.hobgoblin.compiler.ast.untyped.UntypedSumVariantDefinitionNode; +import org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeLevelReferenceNode; + +import static org.zwobble.hobgoblin.compiler.parser.ParserTesting.parseString; +import static org.zwobble.precisely.AssertThat.assertThat; +import static org.zwobble.precisely.Matchers.*; + +public class ParserSumDefinitionTests { + @Test + public void nameIsParsed() { + var source = """ + sum Shape { + }"""; + + var node = parseString( + source, + Parser::parseNamespaceStatement + ); + + assertThat(node, instanceOf( + UntypedSumDefinitionNode.class, + has("name", UntypedSumDefinitionNode::name, equalTo("Shape")) + )); + } + + @Test + public void emptySumHasNoVariants() { + var source = """ + sum Shape { + }"""; + + var node = parseString( + source, + Parser::parseNamespaceStatement + ); + + assertThat(node, instanceOf( + UntypedSumDefinitionNode.class, + has("variants", UntypedSumDefinitionNode::variants, isSequence()) + )); + } + + @Test + public void sumWithVariants() { + var source = """ + sum Shape { + variant Rectangle; + variant Triangle; + }"""; + + var node = parseString( + source, + Parser::parseNamespaceStatement + ); + + assertThat(node, instanceOf( + UntypedSumDefinitionNode.class, + has("variants", UntypedSumDefinitionNode::variants, isSequence( + has( + "type", + UntypedSumVariantDefinitionNode::type, + instanceOf( + UntypedTypeLevelReferenceNode.class, + has("name", UntypedTypeLevelReferenceNode::name, equalTo("Rectangle")) + ) + ), + has( + "type", + UntypedSumVariantDefinitionNode::type, + instanceOf( + UntypedTypeLevelReferenceNode.class, + has("name", UntypedTypeLevelReferenceNode::name, equalTo("Triangle")) + ) + ) + )) + )); + } +} |
