diff options
| author | Michael Williamson <mike@zwobble.org> | 2026-09-27 19:20:17 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2026-09-27 19:24:51 +0100 |
| commit | 275444a59222a078ef65e9458c45d35bfd622745 (patch) | |
| tree | c685dc245bf49f0140b594321ee3369c1b18790f | |
| parent | 4ce7b509105e4b14058d61590e58c1e3c902325d (diff) | |
Parse empty database schema definition
8 files changed, 178 insertions, 2 deletions
diff --git a/hobgoblin/src/ast/untyped.hob b/hobgoblin/src/ast/untyped.hob index 4784e64..1152abb 100644 --- a/hobgoblin/src/ast/untyped.hob +++ b/hobgoblin/src/ast/untyped.hob @@ -17,6 +17,7 @@ struct UntypedImportNode { } sum UntypedNamespaceStatementNode { + variant UntypedDatabaseSchemaDefinitionNode; variant UntypedEnumDefinitionNode; variant UntypedNativeTypeDefinitionNode; variant UntypedStructDefinitionNode; @@ -26,6 +27,12 @@ sum UntypedNamespaceStatementNode { field source: Source; } +struct UntypedDatabaseSchemaDefinitionNode { + field name: String; + field docComment: DocComment; + field source: Source; +} + struct UntypedEnumDefinitionNode { field name: String; field variants: List[UntypedEnumVariantDefinitionNode]; diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedDatabaseSchemaDefinitionNode.java b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedDatabaseSchemaDefinitionNode.java new file mode 100644 index 0000000..7695a42 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedDatabaseSchemaDefinitionNode.java @@ -0,0 +1,44 @@ +// Generated by hobgoblin. + +package org.zwobble.hobgoblin.compiler.ast.untyped; + +// Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNode imports +// Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNode imports + +public record UntypedDatabaseSchemaDefinitionNode( + String name, + 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.UntypedDatabaseSchemaDefinitionNode.Builder arbitrary() { + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNode.Builder("", org.zwobble.hobgoblin.compiler.ast.HobgoblinNativeAst.arbitraryDocComment(), org.zwobble.hobgoblin.compiler.sources.HobgoblinNativeSources.arbitrarySource()); + } + + public record Builder( + String name, + 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.UntypedDatabaseSchemaDefinitionNode build() { + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNode(name, docComment, source); + } + + public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNode.Builder withName(String name) { + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNode.Builder(name, docComment, source); + } + + public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNode.Builder withDocComment(org.zwobble.hobgoblin.compiler.ast.DocComment docComment) { + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNode.Builder(name, docComment, source); + } + + public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNode.Builder withSource(org.zwobble.hobgoblin.compiler.sources.Source source) { + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNode.Builder(name, docComment, source); + } + + // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNode.Builder body + // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNode.Builder body + } + + // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNode body + // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNode body +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedNamespaceStatementNode.java b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedNamespaceStatementNode.java index 4869d3c..3f805bf 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedNamespaceStatementNode.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedNamespaceStatementNode.java @@ -5,7 +5,7 @@ package org.zwobble.hobgoblin.compiler.ast.untyped; // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedNamespaceStatementNode imports // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedNamespaceStatementNode imports -public sealed interface UntypedNamespaceStatementNode permits org.zwobble.hobgoblin.compiler.ast.untyped.UntypedEnumDefinitionNode, org.zwobble.hobgoblin.compiler.ast.untyped.UntypedNativeTypeDefinitionNode, org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode, org.zwobble.hobgoblin.compiler.ast.untyped.UntypedSumDefinitionNode { +public sealed interface UntypedNamespaceStatementNode permits org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNode, org.zwobble.hobgoblin.compiler.ast.untyped.UntypedEnumDefinitionNode, org.zwobble.hobgoblin.compiler.ast.untyped.UntypedNativeTypeDefinitionNode, org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode, org.zwobble.hobgoblin.compiler.ast.untyped.UntypedSumDefinitionNode { public interface Builder { public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedNamespaceStatementNode build(); 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 a80c4bf..9e3c423 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/parser/Parser.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/parser/Parser.java @@ -103,7 +103,9 @@ public class Parser { ) { var docComment = parseDocComment(tokens); - if (tokens.isNext(TokenType.KEYWORD_ENUM)) { + if (tokens.isNext(TokenType.IDENTIFIER, "databaseSchema")) { + return parseDatabaseSchemaDefinition(tokens, docComment); + } else if (tokens.isNext(TokenType.KEYWORD_ENUM)) { return parseEnumDefinition(tokens, docComment); } else if (tokens.isNext(TokenType.KEYWORD_NATIVE)) { return parseNativeTypeDefinition(tokens, docComment); @@ -116,6 +118,28 @@ public class Parser { } } + private static UntypedDatabaseSchemaDefinitionNode parseDatabaseSchemaDefinition( + TokenIterator tokens, + DocComment docComment + ) { + var start = tokens.startPosition(); + + tokens.skip(TokenType.IDENTIFIER, "databaseSchema"); + var name = parseIdentifier(tokens); + tokens.skip(TokenType.SYMBOL_BRACE_OPEN); + + tokens.skip(TokenType.SYMBOL_BRACE_CLOSE); + + var end = tokens.endPosition(); + var source = createSource(start, end); + + return new UntypedDatabaseSchemaDefinitionNode( + name, + docComment, + source + ); + } + private static UntypedEnumDefinitionNode parseEnumDefinition( TokenIterator tokens, DocComment docComment diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/parser/TokenIterator.java b/src/main/java/org/zwobble/hobgoblin/compiler/parser/TokenIterator.java index 43705a1..bf1a0be 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/parser/TokenIterator.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/parser/TokenIterator.java @@ -23,6 +23,11 @@ class TokenIterator { return this.peek().tokenType().equals(tokenType); } + public boolean isNext(TokenType tokenType, String value) { + var token = this.peek(); + return token.tokenType().equals(tokenType) && value.contentEquals(token.charSequence()); + } + public Token next(TokenType tokenType) { var token = peek(); if (token.tokenType().equals(tokenType)) { @@ -44,6 +49,16 @@ class TokenIterator { } } + public void skip(TokenType tokenType, String value) { + var token = peek(); + if (token.tokenType().equals(tokenType) && value.contentEquals(token.charSequence())) { + this.tokenIndex++; + } else { + // TODO: better expected string + throw new UnexpectedTokenError(tokenType.toString(), token); + } + } + public boolean trySkip(TokenType tokenType) { var token = peek(); if (token.tokenType().equals(tokenType)) { diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java index 95ce840..b991a1c 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java @@ -90,6 +90,9 @@ public class TypeChecker { TypeCheckerNamespaceContext context ) { return switch (untyped) { + case UntypedDatabaseSchemaDefinitionNode _ -> + throw new UnsupportedOperationException("TODO"); + case UntypedEnumDefinitionNode untypedEnumDefinitionNode -> declareEnumDefinitionNode(untyped, context); @@ -109,6 +112,9 @@ public class TypeChecker { TypeCheckerNamespaceContext context ) { return switch (untyped) { + case UntypedDatabaseSchemaDefinitionNode _ -> + throw new UnsupportedOperationException("TODO"); + case UntypedEnumDefinitionNode untypedEnumDefinitionNode -> defineEnumDefinition(untypedEnumDefinitionNode, context); diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedDatabaseSchemaDefinitionNodeMatcher.java b/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedDatabaseSchemaDefinitionNodeMatcher.java new file mode 100644 index 0000000..cb132e0 --- /dev/null +++ b/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedDatabaseSchemaDefinitionNodeMatcher.java @@ -0,0 +1,53 @@ +// Generated by hobgoblin. + +package org.zwobble.hobgoblin.compiler.ast.untyped; + +// Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNodeMatcher imports +// Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNodeMatcher imports + +public final class UntypedDatabaseSchemaDefinitionNodeMatcher implements org.zwobble.precisely.Matcher<java.lang.Object> { + public static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNodeMatcher isUntypedDatabaseSchemaDefinitionNode() { + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNodeMatcher(java.util.List.of()); + } + + private final java.util.List<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNode>> submatchers; + + private UntypedDatabaseSchemaDefinitionNodeMatcher( + java.util.List<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNode>> submatchers + ) { + this.submatchers = submatchers; + } + + public org.zwobble.precisely.MatchResult match(java.lang.Object actual) { + return this.toMatcher().match(actual); + } + + public org.zwobble.precisely.TextTree describe() { + return this.toMatcher().describe(); + } + + private org.zwobble.precisely.Matcher<java.lang.Object> toMatcher() { + return org.zwobble.precisely.Matchers.instanceOf(org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNode.class, this.submatchers); + } + + public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNodeMatcher withName(org.zwobble.precisely.Matcher<? super String> name) { + var submatchers = new java.util.ArrayList<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNode>>(this.submatchers); + submatchers.add(org.zwobble.precisely.Matchers.has("name", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNode::name, (org.zwobble.precisely.Matcher) name)); + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNodeMatcher(submatchers); + } + + public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNodeMatcher withDocComment(org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.DocComment> docComment) { + var submatchers = new java.util.ArrayList<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNode>>(this.submatchers); + submatchers.add(org.zwobble.precisely.Matchers.has("docComment", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNode::docComment, (org.zwobble.precisely.Matcher) docComment)); + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNodeMatcher(submatchers); + } + + public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNodeMatcher withSource(org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.sources.Source> source) { + var submatchers = new java.util.ArrayList<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNode>>(this.submatchers); + submatchers.add(org.zwobble.precisely.Matchers.has("source", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNode::source, (org.zwobble.precisely.Matcher) source)); + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNodeMatcher(submatchers); + } + + // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNodeMatcher body + // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNodeMatcher body +} diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserDatabaseSchemaDefinitionTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserDatabaseSchemaDefinitionTests.java new file mode 100644 index 0000000..a43d616 --- /dev/null +++ b/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserDatabaseSchemaDefinitionTests.java @@ -0,0 +1,27 @@ +package org.zwobble.hobgoblin.compiler.parser; + +import org.junit.jupiter.api.Test; +import org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStructDefinitionNode; + +import static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaDefinitionNodeMatcher.isUntypedDatabaseSchemaDefinitionNode; +import static org.zwobble.hobgoblin.compiler.parser.ParserTesting.parseString; +import static org.zwobble.precisely.AssertThat.assertThat; +import static org.zwobble.precisely.Matchers.*; + +public class ParserDatabaseSchemaDefinitionTests { + @Test + public void emptySchema() { + var source = """ + databaseSchema BlogApp { + }"""; + + var node = parseString( + source, + Parser::parseNamespaceStatement + ); + + assertThat(node, isUntypedDatabaseSchemaDefinitionNode() + .withName(equalTo("BlogApp")) + ); + } +} |
