From cf0866c099a601c262dac42ad714b7210b6880f7 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Thu, 23 Apr 2026 11:39:57 +0100 Subject: Parse struct definition fields --- .../ast/untyped/UntypedStructDefinitionNode.java | 3 ++ .../zwobble/hobgoblin/compiler/parser/Parser.java | 35 ++++++++++++++++ .../parser/ParserStructDefinitionTests.java | 46 ++++++++++++++++++++++ 3 files changed, 84 insertions(+) (limited to 'src') 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 e86b141..50f1156 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 @@ -2,8 +2,11 @@ package org.zwobble.hobgoblin.compiler.ast.untyped; import org.zwobble.hobgoblin.compiler.sources.Source; +import java.util.List; + public record UntypedStructDefinitionNode( String name, + List fields, Source source ) implements UntypedNamespaceStatementNode { } 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 90f7f66..7a50bf5 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/parser/Parser.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/parser/Parser.java @@ -39,12 +39,25 @@ public class Parser { static UntypedNamespaceStatementNode parseNamespaceStatement( TokenIterator tokens + ) { + return parseStructDefinition(tokens); + } + + private static UntypedStructDefinitionNode parseStructDefinition( + TokenIterator tokens ) { var start = tokens.startPosition(); tokens.skip(TokenType.KEYWORD_STRUCT); var name = tokens.next(TokenType.IDENTIFIER); tokens.skip(TokenType.SYMBOL_BRACE_OPEN); + + var fields = parseMany( + () -> tokens.isNext(TokenType.SYMBOL_BRACE_CLOSE), + () -> parseStructFieldDefinition(tokens), + () -> true + ); + tokens.skip(TokenType.SYMBOL_BRACE_CLOSE); var end = tokens.endPosition(); @@ -52,6 +65,28 @@ public class Parser { return new UntypedStructDefinitionNode( name.charSequence().toString(), + fields, + source + ); + } + + private static UntypedStructFieldDefinitionNode parseStructFieldDefinition( + TokenIterator tokens + ) { + var start = tokens.startPosition(); + + tokens.skip(TokenType.KEYWORD_FIELD); + var name = tokens.next(TokenType.IDENTIFIER); + tokens.skip(TokenType.SYMBOL_COLON); + var type = parseTypeLevelExpression(tokens); + tokens.skip(TokenType.SYMBOL_SEMICOLON); + + var end = tokens.endPosition(); + var source = createSource(start, end); + + return new UntypedStructFieldDefinitionNode( + name.charSequence().toString(), + type, source ); } 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 8c692fd..9dae394 100644 --- a/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserStructDefinitionTests.java +++ b/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserStructDefinitionTests.java @@ -2,6 +2,8 @@ package org.zwobble.hobgoblin.compiler.parser; import org.junit.jupiter.api.Test; 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.parser.ParserTesting.parseString; import static org.zwobble.precisely.AssertThat.assertThat; @@ -24,4 +26,48 @@ public class ParserStructDefinitionTests { has("name", UntypedStructDefinitionNode::name, equalTo("Point")) )); } + + @Test + public void structWithFields() { + var source = """ + struct Point { + field x: Int; + field y: Int; + }"""; + + var node = parseString( + source, + Parser::parseNamespaceStatement + ); + + assertThat(node, instanceOf( + UntypedStructDefinitionNode.class, + has("fields", UntypedStructDefinitionNode::fields, isSequence( + instanceOf( + UntypedStructFieldDefinitionNode.class, + has("name", UntypedStructFieldDefinitionNode::name, equalTo("x")), + has( + "type", + UntypedStructFieldDefinitionNode::type, + instanceOf( + UntypedTypeLevelReferenceNode.class, + has("name", UntypedTypeLevelReferenceNode::name, equalTo("Int")) + ) + ) + ), + instanceOf( + UntypedStructFieldDefinitionNode.class, + has("name", UntypedStructFieldDefinitionNode::name, equalTo("y")), + has( + "type", + UntypedStructFieldDefinitionNode::type, + instanceOf( + UntypedTypeLevelReferenceNode.class, + has("name", UntypedTypeLevelReferenceNode::name, equalTo("Int")) + ) + ) + ) + )) + )); + } } -- cgit v1.2.3