summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2026-04-23 11:39:57 +0100
committerMichael Williamson <mike@zwobble.org>2026-04-23 11:39:57 +0100
commitcf0866c099a601c262dac42ad714b7210b6880f7 (patch)
treecc81c3c4d214a42d6ab76f57b6c2c26f48e2a4f8 /src
parent503db31edfeb29cf62cb2aae5eb7b4cf195806d4 (diff)
Parse struct definition fields
Diffstat (limited to 'src')
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedStructDefinitionNode.java3
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/parser/Parser.java35
-rw-r--r--src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserStructDefinitionTests.java46
3 files changed, 84 insertions, 0 deletions
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<UntypedStructFieldDefinitionNode> 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
@@ -40,11 +40,24 @@ 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"))
+ )
+ )
+ )
+ ))
+ ));
+ }
}