diff options
5 files changed, 65 insertions, 7 deletions
diff --git a/hobgoblin/src/ast/untyped.hob b/hobgoblin/src/ast/untyped.hob index 10b501a..4784e64 100644 --- a/hobgoblin/src/ast/untyped.hob +++ b/hobgoblin/src/ast/untyped.hob @@ -47,6 +47,7 @@ struct UntypedNativeTypeDefinitionNode { struct UntypedStructDefinitionNode { field name: String; + field typeParams: Option[List[UntypedTypeParamNode]]; field fields: Option[List[UntypedStructFieldDefinitionNode]]; field docComment: DocComment; field source: Source; diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedStructDefinitionNode.java b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedStructDefinitionNode.java index 0239ff8..9742068 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedStructDefinitionNode.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedStructDefinitionNode.java @@ -7,42 +7,52 @@ package org.zwobble.hobgoblin.compiler.ast.untyped; public record UntypedStructDefinitionNode( String name, + java.util.Optional<java.util.List<org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeParamNode>> typeParams, java.util.Optional<java.util.List<org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructFieldDefinitionNode>> fields, org.zwobble.hobgoblin.compiler.ast.DocComment docComment, org.zwobble.hobgoblin.compiler.sources.Source source ) implements org.zwobble.hobgoblin.compiler.ast.untyped.UntypedNamespaceStatementNode { public static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode.Builder arbitrary() { - return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode.Builder("", java.util.Optional.empty(), org.zwobble.hobgoblin.compiler.ast.HobgoblinNativeAst.arbitraryDocComment(), org.zwobble.hobgoblin.compiler.sources.HobgoblinNativeSources.arbitrarySource()); + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode.Builder("", java.util.Optional.empty(), java.util.Optional.empty(), org.zwobble.hobgoblin.compiler.ast.HobgoblinNativeAst.arbitraryDocComment(), org.zwobble.hobgoblin.compiler.sources.HobgoblinNativeSources.arbitrarySource()); } public record Builder( String name, + java.util.Optional<java.util.List<org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeParamNode>> typeParams, java.util.Optional<java.util.List<org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructFieldDefinitionNode>> fields, org.zwobble.hobgoblin.compiler.ast.DocComment docComment, org.zwobble.hobgoblin.compiler.sources.Source source ) implements org.zwobble.hobgoblin.compiler.ast.untyped.UntypedNamespaceStatementNode.Builder { public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode build() { - return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode(name, fields, docComment, source); + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode(name, typeParams, fields, docComment, source); } public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode.Builder withName(String name) { - return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode.Builder(name, fields, docComment, source); + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode.Builder(name, typeParams, fields, docComment, source); + } + + public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode.Builder withTypeParams(java.util.Optional<java.util.List<org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeParamNode>> typeParams) { + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode.Builder(name, typeParams, fields, docComment, source); + } + + public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode.Builder withTypeParams(java.util.List<org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeParamNode> typeParams) { + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode.Builder(name, java.util.Optional.of(typeParams), fields, docComment, source); } public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode.Builder withFields(java.util.Optional<java.util.List<org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructFieldDefinitionNode>> fields) { - return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode.Builder(name, fields, docComment, source); + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode.Builder(name, typeParams, fields, docComment, source); } public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode.Builder withFields(java.util.List<org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructFieldDefinitionNode> fields) { - return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode.Builder(name, java.util.Optional.of(fields), docComment, source); + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode.Builder(name, typeParams, java.util.Optional.of(fields), docComment, source); } public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode.Builder withDocComment(org.zwobble.hobgoblin.compiler.ast.DocComment docComment) { - return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode.Builder(name, fields, docComment, source); + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode.Builder(name, typeParams, fields, docComment, source); } public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode.Builder withSource(org.zwobble.hobgoblin.compiler.sources.Source source) { - return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode.Builder(name, fields, docComment, source); + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode.Builder(name, typeParams, fields, docComment, source); } // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode.Builder body 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 e66d271..12259ad 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/parser/Parser.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/parser/Parser.java @@ -212,6 +212,7 @@ public class Parser { tokens.skip(TokenType.KEYWORD_STRUCT); var name = tokens.next(TokenType.IDENTIFIER); + var typeParams = parseTypeParams(tokens); tokens.skip(TokenType.SYMBOL_BRACE_OPEN); var fields = parseStructDefinitionFields(tokens); @@ -223,6 +224,7 @@ public class Parser { return new UntypedStructDefinitionNode( name.charSequence().toString(), + typeParams, fields, docComment, source diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedStructDefinitionNodeMatcher.java b/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedStructDefinitionNodeMatcher.java index a198802..d559c0d 100644 --- a/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedStructDefinitionNodeMatcher.java +++ b/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedStructDefinitionNodeMatcher.java @@ -36,6 +36,12 @@ public final class UntypedStructDefinitionNodeMatcher implements org.zwobble.pre return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNodeMatcher(submatchers); } + public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNodeMatcher withTypeParams(org.zwobble.precisely.Matcher<? super java.util.Optional<java.util.List<org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeParamNode>>> typeParams) { + var submatchers = new java.util.ArrayList<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode>>(this.submatchers); + submatchers.add(org.zwobble.precisely.Matchers.has("typeParams", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode::typeParams, typeParams)); + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNodeMatcher(submatchers); + } + public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNodeMatcher withFields(org.zwobble.precisely.Matcher<? super java.util.Optional<java.util.List<org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructFieldDefinitionNode>>> fields) { var submatchers = new java.util.ArrayList<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode>>(this.submatchers); submatchers.add(org.zwobble.precisely.Matchers.has("fields", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode::fields, fields)); diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserStructDefinitionTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserStructDefinitionTests.java index 0b8ba5e..2b2fe33 100644 --- a/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserStructDefinitionTests.java +++ b/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserStructDefinitionTests.java @@ -6,6 +6,8 @@ import org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode; import org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructFieldDefinitionNode; import org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeLevelReferenceNode; +import static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNodeMatcher.isUntypedStructDefinitionNode; +import static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeParamNodeMatcher.isUntypedTypeParamNode; import static org.zwobble.hobgoblin.compiler.parser.ParserTesting.parseString; import static org.zwobble.precisely.AssertThat.assertThat; import static org.zwobble.precisely.Matchers.*; @@ -30,6 +32,43 @@ public class ParserStructDefinitionTests { } @Test + public void oneTypeParam() { + var source = """ + struct A[B] { + }"""; + + var node = parseString( + source, + Parser::parseNamespaceStatement + ); + + assertThat(node, isUntypedStructDefinitionNode() + .withTypeParams(isOptionalOf(isSequence( + isUntypedTypeParamNode().withName(equalTo("B")) + ))) + ); + } + + @Test + public void manyTypeParams() { + var source = """ + struct A[B, C] { + }"""; + + var node = parseString( + source, + Parser::parseNamespaceStatement + ); + + assertThat(node, isUntypedStructDefinitionNode() + .withTypeParams(isOptionalOf(isSequence( + isUntypedTypeParamNode().withName(equalTo("B")), + isUntypedTypeParamNode().withName(equalTo("C")) + ))) + ); + } + + @Test public void structWithFields() { var source = """ struct Point { |
