summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/HobgoblinCli.java25
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/HobgoblinCompiler.java19
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/ast/typed/TypedNamespaceStatementNode.java2
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/ast/typed/TypedQueryDefinitionNode.java50
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedCallNode.java60
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedExpressionNode.java18
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedFunctionExpressionNode.java60
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedMemberAccessNode.java48
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedNamespaceStatementNode.java2
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedParamNode.java38
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedQueryDefinitionNode.java72
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedReferenceNode.java38
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedReturnNode.java42
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedStatementNode.java18
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/CodeWriter.java156
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/generators/Generator.java1
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/generators/Stripper.java12
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/generators/java/JavaGenerator.java5
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javapreciselymatchers/JavaPreciselyMatchersGenerator.java9
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatransient0/JavaTransient0Generator.java10
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatypes/JavaTypesGenerator.java9
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/generators/rust/RustGenerator.java5
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/generators/rusttransient0/RustTransient0Generator.java10
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/generators/rusttypes/RustTypesGenerator.java10
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/generators/sqlscripts/SqlScriptsGenerator.java6
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/generators/typescript/TypescriptGenerator.java5
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/generators/typescripttypes/TypescriptTypesGenerator.java10
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/lang/java/JavaWriter.java11
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/lang/rust/RustWriter.java11
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/SqlWriter.java11
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/lang/typescript/TypescriptWriter.java11
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/parser/OperationParser.java15
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/parser/OperatorPrecedence.java5
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/parser/Parser.java225
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/parser/TokenType.java2
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/parser/Tokenizer.java9
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java112
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerNamespaceContext.java7
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypesInfo.java2
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypesInfoInMemory.java23
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/types/DatabaseSchema.java8
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/types/DatabaseSchemaInfo.java6
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/types/HobgoblinNativeTypes.java8
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/types/Table.java8
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/types/TableInfo.java7
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/types/TypeLevelValue.java2
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/types/Types.java8
-rw-r--r--src/test/java/org/zwobble/hobgoblin/compiler/ExampleTests.java13
-rw-r--r--src/test/java/org/zwobble/hobgoblin/compiler/ast/typed/TypedQueryDefinitionNodeMatcher.java59
-rw-r--r--src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedCallNodeMatcher.java53
-rw-r--r--src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedFunctionExpressionNodeMatcher.java53
-rw-r--r--src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedMemberAccessNodeMatcher.java53
-rw-r--r--src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedParamNodeMatcher.java47
-rw-r--r--src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedQueryDefinitionNodeMatcher.java65
-rw-r--r--src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedReferenceNodeMatcher.java47
-rw-r--r--src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedReturnNodeMatcher.java47
-rw-r--r--src/test/java/org/zwobble/hobgoblin/compiler/output/CodeWriterTests.java (renamed from src/test/java/org/zwobble/hobgoblin/compiler/output/lang/CodeWriterTests.java)88
-rw-r--r--src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserCallTests.java61
-rw-r--r--src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserFunctionExpressionTests.java55
-rw-r--r--src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserMemberAccessTests.java26
-rw-r--r--src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserQueryDefinitionTests.java78
-rw-r--r--src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserReferenceTests.java22
-rw-r--r--src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserReturnTests.java25
-rw-r--r--src/test/java/org/zwobble/hobgoblin/compiler/parser/TokenizerTests.java22
-rw-r--r--src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerDatabaseSchemaDefinitionTests.java24
-rw-r--r--src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerQueryDefinitionTests.java40
-rw-r--r--src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerTableDefinitionTests.java20
-rw-r--r--src/test/java/org/zwobble/hobgoblin/compiler/util/SequencedMaps.java23
68 files changed, 2082 insertions, 70 deletions
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/HobgoblinCli.java b/src/main/java/org/zwobble/hobgoblin/compiler/HobgoblinCli.java
index 7e2dcee..9a1e054 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/HobgoblinCli.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/HobgoblinCli.java
@@ -3,6 +3,7 @@ package org.zwobble.hobgoblin.compiler;
import net.sourceforge.argparse4j.ArgumentParsers;
import net.sourceforge.argparse4j.inf.ArgumentParserException;
import net.sourceforge.argparse4j.inf.Namespace;
+import net.sourceforge.argparse4j.inf.Subparser;
import org.zwobble.hobgoblin.compiler.errors.SourceError;
import org.zwobble.hobgoblin.compiler.sources.NullSource;
import org.zwobble.hobgoblin.compiler.util.argparse4j.PathArgumentType;
@@ -31,6 +32,9 @@ public class HobgoblinCli {
case COMPILE -> {
HobgoblinCompiler.compile(sourcePath);
}
+ case STRIP -> {
+ HobgoblinCompiler.strip(sourcePath);
+ }
}
}
@@ -40,12 +44,13 @@ public class HobgoblinCli {
var subparsers = parser.addSubparsers();
- var compileSubParser = subparsers.addParser("compile");
- compileSubParser.setDefault("command", Command.COMPILE);
- compileSubParser
- .addArgument("source")
- .type(new PathArgumentType())
- .required(true);
+ var compileSubparser = subparsers.addParser("compile");
+ compileSubparser.setDefault("command", Command.COMPILE);
+ addSourceArgument(compileSubparser);
+
+ var stripSubparser = subparsers.addParser("strip");
+ stripSubparser.setDefault("command", Command.STRIP);
+ addSourceArgument(stripSubparser);
try {
return parser.parseArgs(args);
@@ -56,7 +61,15 @@ public class HobgoblinCli {
}
}
+ private static void addSourceArgument(Subparser subparser) {
+ subparser
+ .addArgument("source")
+ .type(new PathArgumentType())
+ .required(true);
+ }
+
private enum Command {
COMPILE,
+ STRIP,
}
}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/HobgoblinCompiler.java b/src/main/java/org/zwobble/hobgoblin/compiler/HobgoblinCompiler.java
index 0bd9192..1a34f2b 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/HobgoblinCompiler.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/HobgoblinCompiler.java
@@ -3,6 +3,7 @@ package org.zwobble.hobgoblin.compiler;
import org.zwobble.hobgoblin.compiler.ast.untyped.UntypedNamespaceNode;
import org.zwobble.hobgoblin.compiler.builtins.NativeTypes;
import org.zwobble.hobgoblin.compiler.config.ProjectConfig;
+import org.zwobble.hobgoblin.compiler.output.generators.Stripper;
import org.zwobble.hobgoblin.compiler.parser.Parser;
import org.zwobble.hobgoblin.compiler.typechecker.TypeChecker;
import org.zwobble.hobgoblin.compiler.typechecker.TypeCheckerGlobalContext;
@@ -17,6 +18,7 @@ import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
public class HobgoblinCompiler {
@@ -63,6 +65,23 @@ public class HobgoblinCompiler {
}
}
+ public static void strip(Path projectRoot) throws IOException {
+ var config = ProjectConfig.read(projectRoot);
+ var generators = config.createGenerators();
+
+ // Multiple generators may write the same language to the same
+ // directory, so we de-duplicate strippers rather than asking the
+ // generator to strip directly.
+ var strippers = new HashSet<Stripper>();
+ for (var generator : generators) {
+ strippers.addAll(generator.strippers());
+ }
+
+ for (var stripper : strippers) {
+ stripper.strip();
+ }
+ }
+
static NamespaceName sourceFileNamespaceName(Path sourceDirectory, Path sourceFilePath) {
var relativePath = sourceDirectory.relativize(sourceFilePath);
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/ast/typed/TypedNamespaceStatementNode.java b/src/main/java/org/zwobble/hobgoblin/compiler/ast/typed/TypedNamespaceStatementNode.java
index 8e8bd77..a20416e 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/ast/typed/TypedNamespaceStatementNode.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/ast/typed/TypedNamespaceStatementNode.java
@@ -5,7 +5,7 @@ package org.zwobble.hobgoblin.compiler.ast.typed;
// Custom area start: org.zwobble.hobgoblin.compiler.ast.typed.TypedNamespaceStatementNode imports
// Custom area end: org.zwobble.hobgoblin.compiler.ast.typed.TypedNamespaceStatementNode imports
-public sealed interface TypedNamespaceStatementNode permits org.zwobble.hobgoblin.compiler.ast.typed.TypedDatabaseSchemaDefinitionNode, org.zwobble.hobgoblin.compiler.ast.typed.TypedEnumDefinitionNode, org.zwobble.hobgoblin.compiler.ast.typed.TypedNativeTypeDefinitionNode, org.zwobble.hobgoblin.compiler.ast.typed.TypedStructDefinitionNode, org.zwobble.hobgoblin.compiler.ast.typed.TypedSumDefinitionNode {
+public sealed interface TypedNamespaceStatementNode permits org.zwobble.hobgoblin.compiler.ast.typed.TypedDatabaseSchemaDefinitionNode, org.zwobble.hobgoblin.compiler.ast.typed.TypedEnumDefinitionNode, org.zwobble.hobgoblin.compiler.ast.typed.TypedNativeTypeDefinitionNode, org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode, org.zwobble.hobgoblin.compiler.ast.typed.TypedStructDefinitionNode, org.zwobble.hobgoblin.compiler.ast.typed.TypedSumDefinitionNode {
public interface Builder {
public org.zwobble.hobgoblin.compiler.ast.typed.TypedNamespaceStatementNode build();
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/ast/typed/TypedQueryDefinitionNode.java b/src/main/java/org/zwobble/hobgoblin/compiler/ast/typed/TypedQueryDefinitionNode.java
new file mode 100644
index 0000000..2c3f518
--- /dev/null
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/ast/typed/TypedQueryDefinitionNode.java
@@ -0,0 +1,50 @@
+// Generated by hobgoblin.
+
+package org.zwobble.hobgoblin.compiler.ast.typed;
+
+// Custom area start: org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode imports
+// Custom area end: org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode imports
+
+public record TypedQueryDefinitionNode(
+ String name,
+ org.zwobble.hobgoblin.compiler.types.Table table,
+ org.zwobble.hobgoblin.compiler.ast.DocComment docComment,
+ org.zwobble.hobgoblin.compiler.sources.Source source
+) implements org.zwobble.hobgoblin.compiler.ast.typed.TypedNamespaceStatementNode {
+ public static org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode.Builder arbitrary() {
+ return new org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode.Builder("", org.zwobble.hobgoblin.compiler.types.HobgoblinNativeTypes.arbitraryTable(), org.zwobble.hobgoblin.compiler.ast.HobgoblinNativeAst.arbitraryDocComment(), org.zwobble.hobgoblin.compiler.sources.HobgoblinNativeSources.arbitrarySource());
+ }
+
+ public record Builder(
+ String name,
+ org.zwobble.hobgoblin.compiler.types.Table table,
+ org.zwobble.hobgoblin.compiler.ast.DocComment docComment,
+ org.zwobble.hobgoblin.compiler.sources.Source source
+ ) implements org.zwobble.hobgoblin.compiler.ast.typed.TypedNamespaceStatementNode.Builder {
+ public org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode build() {
+ return new org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode(name, table, docComment, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode.Builder withName(String name) {
+ return new org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode.Builder(name, table, docComment, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode.Builder withTable(org.zwobble.hobgoblin.compiler.types.Table table) {
+ return new org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode.Builder(name, table, docComment, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode.Builder withDocComment(org.zwobble.hobgoblin.compiler.ast.DocComment docComment) {
+ return new org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode.Builder(name, table, docComment, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode.Builder withSource(org.zwobble.hobgoblin.compiler.sources.Source source) {
+ return new org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode.Builder(name, table, docComment, source);
+ }
+
+ // Custom area start: org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode.Builder body
+ // Custom area end: org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode.Builder body
+ }
+
+ // Custom area start: org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode body
+ // Custom area end: org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode body
+}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedCallNode.java b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedCallNode.java
new file mode 100644
index 0000000..2c19adb
--- /dev/null
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedCallNode.java
@@ -0,0 +1,60 @@
+// Generated by hobgoblin.
+
+package org.zwobble.hobgoblin.compiler.ast.untyped;
+
+// Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNode imports
+// Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNode imports
+
+public record UntypedCallNode(
+ org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode receiver,
+ java.util.List<org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode> args,
+ org.zwobble.hobgoblin.compiler.sources.Source source
+) implements org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode {
+ public static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNode.Builder arbitrary() {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNode.Builder(org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNode.arbitrary().build(), java.util.List.of(), org.zwobble.hobgoblin.compiler.sources.HobgoblinNativeSources.arbitrarySource());
+ }
+
+ public record Builder(
+ org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode receiver,
+ java.util.List<org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode> args,
+ org.zwobble.hobgoblin.compiler.sources.Source source
+ ) implements org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode.Builder {
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNode build() {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNode(receiver, args, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNode.Builder withReceiver(org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode receiver) {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNode.Builder(receiver, args, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNode.Builder withReceiver(org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode.Builder receiver) {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNode.Builder(receiver.build(), args, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNode.Builder withArgs(java.util.List<org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode> args) {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNode.Builder(receiver, args, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNode.Builder addArg(org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode arg) {
+ var args = new java.util.ArrayList<org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode>(this.args);
+ args.add(arg);
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNode.Builder(receiver, args, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNode.Builder addArg(org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode.Builder arg) {
+ var args = new java.util.ArrayList<org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode>(this.args);
+ args.add(arg.build());
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNode.Builder(receiver, args, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNode.Builder withSource(org.zwobble.hobgoblin.compiler.sources.Source source) {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNode.Builder(receiver, args, source);
+ }
+
+ // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNode.Builder body
+ // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNode.Builder body
+ }
+
+ // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNode body
+ // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNode body
+}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedExpressionNode.java b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedExpressionNode.java
new file mode 100644
index 0000000..a5c54a0
--- /dev/null
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedExpressionNode.java
@@ -0,0 +1,18 @@
+// Generated by hobgoblin.
+
+package org.zwobble.hobgoblin.compiler.ast.untyped;
+
+// Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode imports
+// Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode imports
+
+public sealed interface UntypedExpressionNode permits org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNode, org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNode, org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNode, org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNode {
+ public interface Builder {
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode build();
+
+ // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode.Builder body
+ // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode.Builder body
+ }
+
+ // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode body
+ // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode body
+}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedFunctionExpressionNode.java b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedFunctionExpressionNode.java
new file mode 100644
index 0000000..4e410f3
--- /dev/null
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedFunctionExpressionNode.java
@@ -0,0 +1,60 @@
+// Generated by hobgoblin.
+
+package org.zwobble.hobgoblin.compiler.ast.untyped;
+
+// Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNode imports
+// Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNode imports
+
+public record UntypedFunctionExpressionNode(
+ java.util.List<org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNode> params,
+ org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode body,
+ org.zwobble.hobgoblin.compiler.sources.Source source
+) implements org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode {
+ public static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNode.Builder arbitrary() {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNode.Builder(java.util.List.of(), org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNode.arbitrary().build(), org.zwobble.hobgoblin.compiler.sources.HobgoblinNativeSources.arbitrarySource());
+ }
+
+ public record Builder(
+ java.util.List<org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNode> params,
+ org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode body,
+ org.zwobble.hobgoblin.compiler.sources.Source source
+ ) implements org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode.Builder {
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNode build() {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNode(params, body, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNode.Builder withParams(java.util.List<org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNode> params) {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNode.Builder(params, body, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNode.Builder addParam(org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNode param) {
+ var params = new java.util.ArrayList<org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNode>(this.params);
+ params.add(param);
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNode.Builder(params, body, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNode.Builder addParam(org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNode.Builder param) {
+ var params = new java.util.ArrayList<org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNode>(this.params);
+ params.add(param.build());
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNode.Builder(params, body, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNode.Builder withBody(org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode body) {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNode.Builder(params, body, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNode.Builder withBody(org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode.Builder body) {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNode.Builder(params, body.build(), source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNode.Builder withSource(org.zwobble.hobgoblin.compiler.sources.Source source) {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNode.Builder(params, body, source);
+ }
+
+ // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNode.Builder body
+ // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNode.Builder body
+ }
+
+ // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNode body
+ // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNode body
+}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedMemberAccessNode.java b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedMemberAccessNode.java
new file mode 100644
index 0000000..6a6e406
--- /dev/null
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedMemberAccessNode.java
@@ -0,0 +1,48 @@
+// Generated by hobgoblin.
+
+package org.zwobble.hobgoblin.compiler.ast.untyped;
+
+// Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNode imports
+// Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNode imports
+
+public record UntypedMemberAccessNode(
+ org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode receiver,
+ String fieldName,
+ org.zwobble.hobgoblin.compiler.sources.Source source
+) implements org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode {
+ public static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNode.Builder arbitrary() {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNode.Builder(org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNode.arbitrary().build(), "", org.zwobble.hobgoblin.compiler.sources.HobgoblinNativeSources.arbitrarySource());
+ }
+
+ public record Builder(
+ org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode receiver,
+ String fieldName,
+ org.zwobble.hobgoblin.compiler.sources.Source source
+ ) implements org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode.Builder {
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNode build() {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNode(receiver, fieldName, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNode.Builder withReceiver(org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode receiver) {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNode.Builder(receiver, fieldName, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNode.Builder withReceiver(org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode.Builder receiver) {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNode.Builder(receiver.build(), fieldName, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNode.Builder withFieldName(String fieldName) {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNode.Builder(receiver, fieldName, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNode.Builder withSource(org.zwobble.hobgoblin.compiler.sources.Source source) {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNode.Builder(receiver, fieldName, source);
+ }
+
+ // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNode.Builder body
+ // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNode.Builder body
+ }
+
+ // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNode body
+ // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNode 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 3f805bf..2e78f39 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.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 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.UntypedQueryDefinitionNode, 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/ast/untyped/UntypedParamNode.java b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedParamNode.java
new file mode 100644
index 0000000..068097f
--- /dev/null
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedParamNode.java
@@ -0,0 +1,38 @@
+// Generated by hobgoblin.
+
+package org.zwobble.hobgoblin.compiler.ast.untyped;
+
+// Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNode imports
+// Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNode imports
+
+public record UntypedParamNode(
+ String name,
+ org.zwobble.hobgoblin.compiler.sources.Source source
+) {
+ public static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNode.Builder arbitrary() {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNode.Builder("", org.zwobble.hobgoblin.compiler.sources.HobgoblinNativeSources.arbitrarySource());
+ }
+
+ public record Builder(
+ String name,
+ org.zwobble.hobgoblin.compiler.sources.Source source
+ ) {
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNode build() {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNode(name, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNode.Builder withName(String name) {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNode.Builder(name, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNode.Builder withSource(org.zwobble.hobgoblin.compiler.sources.Source source) {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNode.Builder(name, source);
+ }
+
+ // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNode.Builder body
+ // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNode.Builder body
+ }
+
+ // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNode body
+ // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNode body
+}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedQueryDefinitionNode.java b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedQueryDefinitionNode.java
new file mode 100644
index 0000000..ee1ddbc
--- /dev/null
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedQueryDefinitionNode.java
@@ -0,0 +1,72 @@
+// Generated by hobgoblin.
+
+package org.zwobble.hobgoblin.compiler.ast.untyped;
+
+// Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode imports
+// Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode imports
+
+public record UntypedQueryDefinitionNode(
+ String name,
+ org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeLevelExpressionNode databaseSchema,
+ java.util.List<org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStatementNode> statements,
+ 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.UntypedQueryDefinitionNode.Builder arbitrary() {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode.Builder("", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeLevelReferenceNode.arbitrary().build(), java.util.List.of(), org.zwobble.hobgoblin.compiler.ast.HobgoblinNativeAst.arbitraryDocComment(), org.zwobble.hobgoblin.compiler.sources.HobgoblinNativeSources.arbitrarySource());
+ }
+
+ public record Builder(
+ String name,
+ org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeLevelExpressionNode databaseSchema,
+ java.util.List<org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStatementNode> statements,
+ 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.UntypedQueryDefinitionNode build() {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode(name, databaseSchema, statements, docComment, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode.Builder withName(String name) {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode.Builder(name, databaseSchema, statements, docComment, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode.Builder withDatabaseSchema(org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeLevelExpressionNode databaseSchema) {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode.Builder(name, databaseSchema, statements, docComment, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode.Builder withDatabaseSchema(org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeLevelExpressionNode.Builder databaseSchema) {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode.Builder(name, databaseSchema.build(), statements, docComment, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode.Builder withStatements(java.util.List<org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStatementNode> statements) {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode.Builder(name, databaseSchema, statements, docComment, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode.Builder addStatement(org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStatementNode statement) {
+ var statements = new java.util.ArrayList<org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStatementNode>(this.statements);
+ statements.add(statement);
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode.Builder(name, databaseSchema, statements, docComment, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode.Builder addStatement(org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStatementNode.Builder statement) {
+ var statements = new java.util.ArrayList<org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStatementNode>(this.statements);
+ statements.add(statement.build());
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode.Builder(name, databaseSchema, statements, docComment, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode.Builder withDocComment(org.zwobble.hobgoblin.compiler.ast.DocComment docComment) {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode.Builder(name, databaseSchema, statements, docComment, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode.Builder withSource(org.zwobble.hobgoblin.compiler.sources.Source source) {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode.Builder(name, databaseSchema, statements, docComment, source);
+ }
+
+ // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode.Builder body
+ // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode.Builder body
+ }
+
+ // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode body
+ // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode body
+}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedReferenceNode.java b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedReferenceNode.java
new file mode 100644
index 0000000..edd3066
--- /dev/null
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedReferenceNode.java
@@ -0,0 +1,38 @@
+// Generated by hobgoblin.
+
+package org.zwobble.hobgoblin.compiler.ast.untyped;
+
+// Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNode imports
+// Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNode imports
+
+public record UntypedReferenceNode(
+ String name,
+ org.zwobble.hobgoblin.compiler.sources.Source source
+) implements org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode {
+ public static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNode.Builder arbitrary() {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNode.Builder("", org.zwobble.hobgoblin.compiler.sources.HobgoblinNativeSources.arbitrarySource());
+ }
+
+ public record Builder(
+ String name,
+ org.zwobble.hobgoblin.compiler.sources.Source source
+ ) implements org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode.Builder {
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNode build() {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNode(name, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNode.Builder withName(String name) {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNode.Builder(name, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNode.Builder withSource(org.zwobble.hobgoblin.compiler.sources.Source source) {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNode.Builder(name, source);
+ }
+
+ // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNode.Builder body
+ // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNode.Builder body
+ }
+
+ // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNode body
+ // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNode body
+}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedReturnNode.java b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedReturnNode.java
new file mode 100644
index 0000000..f115b24
--- /dev/null
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedReturnNode.java
@@ -0,0 +1,42 @@
+// Generated by hobgoblin.
+
+package org.zwobble.hobgoblin.compiler.ast.untyped;
+
+// Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNode imports
+// Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNode imports
+
+public record UntypedReturnNode(
+ org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode expression,
+ org.zwobble.hobgoblin.compiler.sources.Source source
+) implements org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStatementNode {
+ public static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNode.Builder arbitrary() {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNode.Builder(org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNode.arbitrary().build(), org.zwobble.hobgoblin.compiler.sources.HobgoblinNativeSources.arbitrarySource());
+ }
+
+ public record Builder(
+ org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode expression,
+ org.zwobble.hobgoblin.compiler.sources.Source source
+ ) implements org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStatementNode.Builder {
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNode build() {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNode(expression, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNode.Builder withExpression(org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode expression) {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNode.Builder(expression, source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNode.Builder withExpression(org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode.Builder expression) {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNode.Builder(expression.build(), source);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNode.Builder withSource(org.zwobble.hobgoblin.compiler.sources.Source source) {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNode.Builder(expression, source);
+ }
+
+ // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNode.Builder body
+ // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNode.Builder body
+ }
+
+ // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNode body
+ // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNode body
+}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedStatementNode.java b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedStatementNode.java
new file mode 100644
index 0000000..8121f93
--- /dev/null
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedStatementNode.java
@@ -0,0 +1,18 @@
+// Generated by hobgoblin.
+
+package org.zwobble.hobgoblin.compiler.ast.untyped;
+
+// Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStatementNode imports
+// Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStatementNode imports
+
+public sealed interface UntypedStatementNode permits org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNode {
+ public interface Builder {
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStatementNode build();
+
+ // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStatementNode.Builder body
+ // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStatementNode.Builder body
+ }
+
+ // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStatementNode body
+ // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStatementNode body
+}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/CodeWriter.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/CodeWriter.java
index 81fd091..551683e 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/output/CodeWriter.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/CodeWriter.java
@@ -1,5 +1,7 @@
package org.zwobble.hobgoblin.compiler.output;
+import org.zwobble.hobgoblin.compiler.output.generators.Stripper;
+
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
@@ -10,6 +12,30 @@ import java.nio.file.Path;
import java.util.*;
public class CodeWriter implements AutoCloseable {
+ public static class CodeWriterConfig {
+ private final String header;
+ private final String customAreaStart;
+ private final String customAreaEnd;
+
+ public CodeWriterConfig(String lineCommentStart) {
+ this.header = lineCommentStart + " Generated by hobgoblin.\n\n";
+ this.customAreaStart = lineCommentStart + " Custom area start: ";
+ this.customAreaEnd = lineCommentStart + " Custom area end: ";
+ }
+
+ public String header() {
+ return this.header;
+ }
+
+ public String customAreaStart() {
+ return customAreaStart;
+ }
+
+ public String customAreaEnd() {
+ return customAreaEnd;
+ }
+ }
+
public interface CodeWriterFile {
String readString() throws IOException;
Writer openWriter() throws IOException;
@@ -50,26 +76,26 @@ public class CodeWriter implements AutoCloseable {
}
public record CustomAreas(
- Map<String, List<String>> existing,
- String customAreaStart,
- String customAreaEnd
+ SequencedMap<String, List<String>> existing,
+ CodeWriterConfig config
) {
public static CustomAreas read(
String existingString,
- String customAreaStart,
- String customAreaEnd
+ CodeWriterConfig config
) {
- var existing = new HashMap<String, List<String>>();
+ var existing = new LinkedHashMap<String, List<String>>();
Iterable<String> lines = () -> existingString.lines().iterator();
Optional<String> name = Optional.empty();
var customAreaLines = new ArrayList<String>();
for (var line : lines) {
var trimmedLine = line.trim();
- if (trimmedLine.startsWith(customAreaStart)) {
- name = Optional.of(trimmedLine.substring(customAreaStart.length()));
- } else if (name.isPresent() && trimmedLine.startsWith(customAreaEnd + name.get())) {
- existing.put(name.get(), customAreaLines);
+ if (trimmedLine.startsWith(config.customAreaStart)) {
+ name = Optional.of(trimmedLine.substring(config.customAreaStart.length()));
+ } else if (name.isPresent() && trimmedLine.startsWith(config.customAreaEnd + name.get())) {
+ if (!customAreaLines.isEmpty()) {
+ existing.put(name.get(), customAreaLines);
+ }
customAreaLines = new ArrayList<>();
name = Optional.empty();
} else if (name.isPresent()) {
@@ -77,14 +103,19 @@ public class CodeWriter implements AutoCloseable {
}
}
- return new CustomAreas(existing, customAreaStart, customAreaEnd);
+ return new CustomAreas(existing, config);
}
- public static CustomAreas empty(
- String customAreaStart,
- String customAreaEnd
- ) {
- return new CustomAreas(Map.of(), customAreaStart, customAreaEnd);
+ public static CustomAreas empty(CodeWriterConfig config) {
+ return new CustomAreas(new LinkedHashMap<>(), config);
+ }
+
+ public String customAreaStart() {
+ return this.config.customAreaStart;
+ }
+
+ public String customAreaEnd() {
+ return this.config.customAreaEnd;
}
public Iterable<String> lines(String name) {
@@ -103,7 +134,7 @@ public class CodeWriter implements AutoCloseable {
public static void writeTo(
Path path,
- String lineCommentStart,
+ CodeWriterConfig config,
Write write
) throws IOException {
writeTo(
@@ -119,43 +150,104 @@ public class CodeWriter implements AutoCloseable {
return new FileWriter(path.toFile());
}
},
- lineCommentStart,
+ config,
write
);
}
public static void writeTo(
CodeWriterFile file,
- String lineCommentStart,
+ CodeWriterConfig config,
Write write
) throws IOException {
var originalContents = readFile(file);
- var header = lineCommentStart + " Generated by hobgoblin.\n\n";
- if (originalContents.isPresent() && !originalContents.get().startsWith(header)) {
+ if (originalContents.isPresent() && !isGeneratedFile(originalContents.get(), config)) {
return;
}
- var customAreaStart = lineCommentStart + " Custom area start: ";
- var customAreaEnd = lineCommentStart + " Custom area end: ";
-
- var customAreas = readCustomAreas(file, customAreaStart, customAreaEnd);
+ var customAreas = readCustomAreas(file, config);
try (var writer = file.openWriter()) {
// TODO: warn if custom areas are unused?
- write.write(new CodeWriter(writer, header, customAreas));
+ write.write(new CodeWriter(writer, config.header, customAreas));
+ }
+ }
+
+ private static boolean isGeneratedFile(String contents, CodeWriterConfig config) {
+ return contents.startsWith(config.header);
+ }
+
+ public static Stripper stripper(
+ Path outputPath,
+ CodeWriterConfig config
+ ) {
+ return new Stripper(outputPath, config);
+ }
+
+ public static void strip(Path outputPath, CodeWriterConfig config) throws IOException {
+ try (var filesStream = Files.walk(outputPath)) {
+ var filesIterator = filesStream.iterator();
+ while (filesIterator.hasNext()) {
+ var path = filesIterator.next();
+ if (path.toFile().isFile()) {
+ // TODO: filter by extension?
+ // TODO: don't read entire string if not necessary.
+ var contents = Files.readString(path);
+ switch (stripFileContents(contents, config)) {
+ case StripResult.Delete _ -> {
+ Files.delete(path);
+ }
+ case StripResult.NewContent newContent -> {
+ Files.writeString(path, newContent.newContents);
+ }
+ case StripResult.Unchanged _ -> {
+ }
+ }
+ }
+ }
+ }
+ }
+
+ sealed interface StripResult {
+ record Unchanged() implements StripResult {}
+ record Delete() implements StripResult {}
+ record NewContent(String newContents) implements StripResult {}
+ }
+
+ static StripResult stripFileContents(String contents, CodeWriterConfig config) {
+ if (!isGeneratedFile(contents, config)) {
+ return new StripResult.Unchanged();
+ }
+
+ var stringWriter = new StringWriter();
+ var customAreas = CustomAreas.read(contents, config);
+ if (customAreas.existing.isEmpty()) {
+ return new StripResult.Delete();
+ }
+
+ var writer = new CodeWriter(stringWriter, config.header, customAreas);
+ try {
+ writer.writeHeader();
+ for (var customAreaName : customAreas.existing.keySet()) {
+ writer.writeCustomArea(customAreaName);
+ }
+ return new StripResult.NewContent(stringWriter.toString());
+ } catch (IOException exception) {
+ // In theory, writing to a StringWriter will always succeed, so
+ // we don't need to handle this especially well.
+ throw new RuntimeException(exception);
}
}
private static CustomAreas readCustomAreas(
CodeWriterFile file,
- String customAreaStart,
- String customAreaEnd
+ CodeWriterConfig config
) throws IOException {
try {
var contents = file.readString();
- return CustomAreas.read(contents, customAreaStart, customAreaEnd);
+ return CustomAreas.read(contents, config);
} catch (NoSuchFileException exception) {
- return CustomAreas.empty(customAreaStart, customAreaEnd);
+ return CustomAreas.empty(config);
}
}
@@ -210,7 +302,7 @@ public class CodeWriter implements AutoCloseable {
}
public void writeCustomArea(String name) throws IOException {
- this.write(this.customAreas.customAreaStart);
+ this.write(this.customAreas.customAreaStart());
this.write(name);
for (var line : this.customAreas.lines(name)) {
@@ -219,7 +311,7 @@ public class CodeWriter implements AutoCloseable {
}
this.newLine();
- this.write(this.customAreas.customAreaEnd);
+ this.write(this.customAreas.customAreaEnd());
this.write(name);
this.newLine();
}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/Generator.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/Generator.java
index 4a73000..dd8f46d 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/Generator.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/Generator.java
@@ -8,4 +8,5 @@ import java.util.List;
public interface Generator {
void generate(List<TypedNamespaceNode> namespaces, TypesInfo typesInfo) throws IOException;
+ List<Stripper> strippers();
}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/Stripper.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/Stripper.java
new file mode 100644
index 0000000..27241eb
--- /dev/null
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/Stripper.java
@@ -0,0 +1,12 @@
+package org.zwobble.hobgoblin.compiler.output.generators;
+
+import org.zwobble.hobgoblin.compiler.output.CodeWriter;
+
+import java.io.IOException;
+import java.nio.file.Path;
+
+public record Stripper(Path path, CodeWriter.CodeWriterConfig codeWriterConfig) {
+ public void strip() throws IOException {
+ CodeWriter.strip(path, codeWriterConfig);
+ }
+}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/java/JavaGenerator.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/java/JavaGenerator.java
index 61fc237..f202f61 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/java/JavaGenerator.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/java/JavaGenerator.java
@@ -1,6 +1,7 @@
package org.zwobble.hobgoblin.compiler.output.generators.java;
import org.zwobble.hobgoblin.compiler.builtins.NativeTypes;
+import org.zwobble.hobgoblin.compiler.output.generators.Stripper;
import org.zwobble.hobgoblin.compiler.output.lang.java.JavaWriter;
import org.zwobble.hobgoblin.compiler.output.lang.java.ast.*;
import org.zwobble.hobgoblin.compiler.types.*;
@@ -40,6 +41,10 @@ public class JavaGenerator {
}
}
+ public List<Stripper> strippers(Path sourceRootDirectory) {
+ return List.of(JavaWriter.stripper(sourceRootDirectory));
+ }
+
public JavaPackageName namespaceToJavaPackageName(NamespaceName namespaceName) {
var ancestorNamespaceName = namespaceName;
var remainingNamespaceNameParts = new ArrayList<String>();
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javapreciselymatchers/JavaPreciselyMatchersGenerator.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javapreciselymatchers/JavaPreciselyMatchersGenerator.java
index 1ae368e..9b751d0 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javapreciselymatchers/JavaPreciselyMatchersGenerator.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javapreciselymatchers/JavaPreciselyMatchersGenerator.java
@@ -5,6 +5,7 @@ import org.zwobble.hobgoblin.compiler.ast.typed.*;
import org.zwobble.hobgoblin.compiler.config.OutputConfig;
import org.zwobble.hobgoblin.compiler.output.generators.Generator;
import org.zwobble.hobgoblin.compiler.output.generators.GeneratorDefinition;
+import org.zwobble.hobgoblin.compiler.output.generators.Stripper;
import org.zwobble.hobgoblin.compiler.output.generators.java.JavaGenerator;
import org.zwobble.hobgoblin.compiler.output.generators.java.JavaGeneratorConfig;
import org.zwobble.hobgoblin.compiler.output.lang.java.ast.*;
@@ -80,6 +81,11 @@ public class JavaPreciselyMatchersGenerator implements Generator {
}
}
+ @Override
+ public List<Stripper> strippers() {
+ return this.javaGenerator.strippers(this.sourceRootDirectory);
+ }
+
private List<JavaCompilationUnit> generateNamespace(TypedNamespaceNode namespace, Context context) {
var javaCompilationUnits = new ArrayList<JavaCompilationUnit>();
@@ -94,6 +100,9 @@ public class JavaPreciselyMatchersGenerator implements Generator {
case TypedNativeTypeDefinitionNode _ -> {
}
+ case TypedQueryDefinitionNode _ -> {
+ }
+
case TypedStructDefinitionNode structDefinition -> {
var javaCompilationUnit = new JavaCompilationUnit(
generateStructDefinition(structDefinition, context)
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatransient0/JavaTransient0Generator.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatransient0/JavaTransient0Generator.java
index 38bf9b6..0220ba9 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatransient0/JavaTransient0Generator.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatransient0/JavaTransient0Generator.java
@@ -6,6 +6,7 @@ import org.zwobble.hobgoblin.compiler.builtins.NativeTypes;
import org.zwobble.hobgoblin.compiler.config.OutputConfig;
import org.zwobble.hobgoblin.compiler.output.generators.Generator;
import org.zwobble.hobgoblin.compiler.output.generators.GeneratorDefinition;
+import org.zwobble.hobgoblin.compiler.output.generators.Stripper;
import org.zwobble.hobgoblin.compiler.output.generators.java.JavaGenerator;
import org.zwobble.hobgoblin.compiler.output.generators.java.JavaGeneratorConfig;
import org.zwobble.hobgoblin.compiler.output.generators.transient0.Transient0TypeLevelValuesUnsupported;
@@ -96,6 +97,11 @@ public class JavaTransient0Generator implements Generator {
}
}
+ @Override
+ public List<Stripper> strippers() {
+ return this.javaGenerator.strippers(this.sourceRootDirectory);
+ }
+
private void write(List<JavaCompilationUnit> javaCompilationUnits) throws IOException {
JavaGenerator.write(this.sourceRootDirectory, javaCompilationUnits);
}
@@ -662,6 +668,10 @@ public class JavaTransient0Generator implements Generator {
yield List.of();
}
+ case TypedQueryDefinitionNode _ -> {
+ yield List.of();
+ }
+
case TypedStructDefinitionNode structDefinition -> {
yield List.of(
generateEncodeStructMethod(structDefinition, context),
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatypes/JavaTypesGenerator.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatypes/JavaTypesGenerator.java
index e3f54cf..17065e0 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatypes/JavaTypesGenerator.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatypes/JavaTypesGenerator.java
@@ -7,6 +7,7 @@ import org.zwobble.hobgoblin.compiler.builtins.NativeTypes;
import org.zwobble.hobgoblin.compiler.config.OutputConfig;
import org.zwobble.hobgoblin.compiler.output.generators.Generator;
import org.zwobble.hobgoblin.compiler.output.generators.GeneratorDefinition;
+import org.zwobble.hobgoblin.compiler.output.generators.Stripper;
import org.zwobble.hobgoblin.compiler.output.generators.java.JavaGenerator;
import org.zwobble.hobgoblin.compiler.output.generators.java.JavaGeneratorConfig;
import org.zwobble.hobgoblin.compiler.output.generators.java.JavaNativeTypeConfig;
@@ -90,6 +91,11 @@ public class JavaTypesGenerator implements Generator {
}
}
+ @Override
+ public List<Stripper> strippers() {
+ return this.javaGenerator.strippers(this.sourceRootDirectory);
+ }
+
private List<JavaCompilationUnit> generateNamespace(TypedNamespaceNode namespace, Context context) {
var javaCompilationUnits = new ArrayList<JavaCompilationUnit>();
@@ -109,6 +115,9 @@ public class JavaTypesGenerator implements Generator {
case TypedNativeTypeDefinitionNode nativeTypeDefinition -> {
}
+ case TypedQueryDefinitionNode _ -> {
+ }
+
case TypedStructDefinitionNode structDefinition -> {
var javaCompilationUnit = new JavaCompilationUnit(
generateStructDefinition(structDefinition, context)
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/rust/RustGenerator.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/rust/RustGenerator.java
index fae9066..1fd342f 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/rust/RustGenerator.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/rust/RustGenerator.java
@@ -1,5 +1,6 @@
package org.zwobble.hobgoblin.compiler.output.generators.rust;
+import org.zwobble.hobgoblin.compiler.output.generators.Stripper;
import org.zwobble.hobgoblin.compiler.output.lang.rust.RustWriter;
import org.zwobble.hobgoblin.compiler.output.lang.rust.ast.*;
import org.zwobble.hobgoblin.compiler.types.*;
@@ -32,6 +33,10 @@ public class RustGenerator {
});
}
+ public List<Stripper> strippers() {
+ return List.of(RustWriter.stripper(this.outputPath));
+ }
+
public RustPath generateRustTypeExpression(Type type) {
return switch (type) {
case ConstructedType constructedType -> {
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/rusttransient0/RustTransient0Generator.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/rusttransient0/RustTransient0Generator.java
index 8ecc7cc..8f2f4ad 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/rusttransient0/RustTransient0Generator.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/rusttransient0/RustTransient0Generator.java
@@ -5,6 +5,7 @@ import org.zwobble.hobgoblin.compiler.builtins.NativeTypes;
import org.zwobble.hobgoblin.compiler.config.OutputConfig;
import org.zwobble.hobgoblin.compiler.output.generators.Generator;
import org.zwobble.hobgoblin.compiler.output.generators.GeneratorDefinition;
+import org.zwobble.hobgoblin.compiler.output.generators.Stripper;
import org.zwobble.hobgoblin.compiler.output.generators.rust.RustGenerator;
import org.zwobble.hobgoblin.compiler.output.generators.rust.RustGeneratorConfig;
import org.zwobble.hobgoblin.compiler.output.generators.transient0.Transient0TypeLevelValuesUnsupported;
@@ -90,6 +91,11 @@ public class RustTransient0Generator implements Generator {
}
}
+ @Override
+ public List<Stripper> strippers() {
+ return this.rustGenerator.strippers();
+ }
+
private void generateBuiltins() throws IOException {
var rustModuleName = builtinsModuleName();
var rustModule = new RustModule(
@@ -417,6 +423,10 @@ public class RustTransient0Generator implements Generator {
yield Stream.of();
}
+ case TypedQueryDefinitionNode _ -> {
+ yield Stream.of();
+ }
+
case TypedStructDefinitionNode structDefinition -> {
yield Stream.of(
generateEncodeStructFunction(structDefinition),
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/rusttypes/RustTypesGenerator.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/rusttypes/RustTypesGenerator.java
index f01e143..f57ec33 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/rusttypes/RustTypesGenerator.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/rusttypes/RustTypesGenerator.java
@@ -4,6 +4,7 @@ import org.zwobble.hobgoblin.compiler.ast.typed.*;
import org.zwobble.hobgoblin.compiler.config.OutputConfig;
import org.zwobble.hobgoblin.compiler.output.generators.Generator;
import org.zwobble.hobgoblin.compiler.output.generators.GeneratorDefinition;
+import org.zwobble.hobgoblin.compiler.output.generators.Stripper;
import org.zwobble.hobgoblin.compiler.output.generators.rust.RustGenerator;
import org.zwobble.hobgoblin.compiler.output.generators.rust.RustGeneratorConfig;
import org.zwobble.hobgoblin.compiler.output.lang.rust.ast.*;
@@ -76,6 +77,11 @@ public class RustTypesGenerator implements Generator {
}
}
+ @Override
+ public List<Stripper> strippers() {
+ return this.rustGenerator.strippers();
+ }
+
private RustModule generateNamespace(TypedNamespaceNode namespace, TypesInfo typesInfo) {
var rustModuleName = this.rustGenerator.namespaceNameToRustCrateModulePath(namespace.namespaceName());
@@ -103,6 +109,10 @@ public class RustTypesGenerator implements Generator {
yield List.of();
}
+ case TypedQueryDefinitionNode _ -> {
+ yield List.of();
+ }
+
case TypedStructDefinitionNode structDefinition -> {
yield generateStructDefinition(structDefinition);
}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/sqlscripts/SqlScriptsGenerator.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/sqlscripts/SqlScriptsGenerator.java
index 60daf40..5089271 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/sqlscripts/SqlScriptsGenerator.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/sqlscripts/SqlScriptsGenerator.java
@@ -7,6 +7,7 @@ import org.zwobble.hobgoblin.compiler.ast.typed.TypedTableDefinitionNode;
import org.zwobble.hobgoblin.compiler.config.OutputConfig;
import org.zwobble.hobgoblin.compiler.output.generators.Generator;
import org.zwobble.hobgoblin.compiler.output.generators.GeneratorDefinition;
+import org.zwobble.hobgoblin.compiler.output.generators.Stripper;
import org.zwobble.hobgoblin.compiler.output.generators.sql.SqlGenerator;
import org.zwobble.hobgoblin.compiler.output.lang.sql.SqlWriter;
import org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlScript;
@@ -80,6 +81,11 @@ public class SqlScriptsGenerator implements Generator {
}
}
+ @Override
+ public List<Stripper> strippers() {
+ return List.of(SqlWriter.stripper(this.outputPath));
+ }
+
private void generateDatabaseSchemaDefinition(
TypedDatabaseSchemaDefinitionNode databaseSchemaDefinition,
NamespaceName namespaceName,
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/typescript/TypescriptGenerator.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/typescript/TypescriptGenerator.java
index 68d1610..a16d1f3 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/typescript/TypescriptGenerator.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/typescript/TypescriptGenerator.java
@@ -1,6 +1,7 @@
package org.zwobble.hobgoblin.compiler.output.generators.typescript;
import org.zwobble.hobgoblin.compiler.builtins.NativeTypes;
+import org.zwobble.hobgoblin.compiler.output.generators.Stripper;
import org.zwobble.hobgoblin.compiler.output.lang.typescript.TypescriptTypes;
import org.zwobble.hobgoblin.compiler.output.lang.typescript.TypescriptWriter;
import org.zwobble.hobgoblin.compiler.output.lang.typescript.ast.*;
@@ -33,6 +34,10 @@ public class TypescriptGenerator {
TypescriptWriter.writeTo(path, writer -> writer.writeModule(module));
}
+ public List<Stripper> strippers() {
+ return List.of(TypescriptWriter.stripper(this.outputPath));
+ }
+
public record RequiredType(SimpleType type, TypescriptIdentifier importName) {}
public static class Context {
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/typescripttypes/TypescriptTypesGenerator.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/typescripttypes/TypescriptTypesGenerator.java
index 6dd8592..cbdf016 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/typescripttypes/TypescriptTypesGenerator.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/typescripttypes/TypescriptTypesGenerator.java
@@ -4,6 +4,7 @@ import org.zwobble.hobgoblin.compiler.ast.typed.*;
import org.zwobble.hobgoblin.compiler.config.OutputConfig;
import org.zwobble.hobgoblin.compiler.output.generators.Generator;
import org.zwobble.hobgoblin.compiler.output.generators.GeneratorDefinition;
+import org.zwobble.hobgoblin.compiler.output.generators.Stripper;
import org.zwobble.hobgoblin.compiler.output.generators.typescript.TypescriptGenerator;
import org.zwobble.hobgoblin.compiler.output.generators.typescript.TypescriptGeneratorConfig;
import org.zwobble.hobgoblin.compiler.output.lang.typescript.TypescriptTypes;
@@ -78,6 +79,11 @@ public class TypescriptTypesGenerator implements Generator {
}
}
+ @Override
+ public List<Stripper> strippers() {
+ return this.typescriptGenerator.strippers();
+ }
+
private TypescriptModule generateNamespace(
TypedNamespaceNode namespace,
TypesInfo typesInfo
@@ -148,6 +154,10 @@ public class TypescriptTypesGenerator implements Generator {
return List.of();
}
+ case TypedQueryDefinitionNode _ -> {
+ return List.of();
+ }
+
case TypedStructDefinitionNode structDefinition -> {
return generateStructDefinition(structDefinition, context);
}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/java/JavaWriter.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/java/JavaWriter.java
index d2f46ad..2d17085 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/java/JavaWriter.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/java/JavaWriter.java
@@ -2,6 +2,7 @@ package org.zwobble.hobgoblin.compiler.output.lang.java;
import org.zwobble.hobgoblin.compiler.ast.DocComment;
import org.zwobble.hobgoblin.compiler.output.CodeWriter;
+import org.zwobble.hobgoblin.compiler.output.generators.Stripper;
import org.zwobble.hobgoblin.compiler.output.lang.java.ast.*;
import java.io.IOException;
@@ -14,6 +15,8 @@ import static org.zwobble.hobgoblin.compiler.output.CodeWriter.writeWithSeparato
public class JavaWriter implements AutoCloseable {
private static final String LINE_COMMENT_START = "//";
+ private static final CodeWriter.CodeWriterConfig CONFIG =
+ new CodeWriter.CodeWriterConfig(LINE_COMMENT_START);
public interface Write {
void write(JavaWriter writer) throws IOException;
@@ -22,7 +25,7 @@ public class JavaWriter implements AutoCloseable {
public static void writeTo(Path path, Write write) throws IOException {
CodeWriter.writeTo(
path,
- LINE_COMMENT_START,
+ CONFIG,
writer -> write.write(new JavaWriter(writer))
);
}
@@ -30,11 +33,15 @@ public class JavaWriter implements AutoCloseable {
public static void writeTo(CodeWriter.CodeWriterFile file, Write write) throws IOException {
CodeWriter.writeTo(
file,
- LINE_COMMENT_START,
+ CONFIG,
writer -> write.write(new JavaWriter(writer))
);
}
+ public static Stripper stripper(Path sourceRootDirectory) {
+ return CodeWriter.stripper(sourceRootDirectory, CONFIG);
+ }
+
private final CodeWriter writer;
public JavaWriter(CodeWriter writer) {
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/rust/RustWriter.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/rust/RustWriter.java
index df8aa8c..076e150 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/rust/RustWriter.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/rust/RustWriter.java
@@ -2,6 +2,7 @@ package org.zwobble.hobgoblin.compiler.output.lang.rust;
import org.zwobble.hobgoblin.compiler.ast.DocComment;
import org.zwobble.hobgoblin.compiler.output.CodeWriter;
+import org.zwobble.hobgoblin.compiler.output.generators.Stripper;
import org.zwobble.hobgoblin.compiler.output.lang.rust.ast.*;
import java.io.IOException;
@@ -14,6 +15,8 @@ import static org.zwobble.hobgoblin.compiler.output.CodeWriter.writeWithSeparato
public class RustWriter implements AutoCloseable {
private static final String LINE_COMMENT_START = "//";
+ private static final CodeWriter.CodeWriterConfig CONFIG =
+ new CodeWriter.CodeWriterConfig(LINE_COMMENT_START);
public interface Write {
void write(RustWriter writer) throws IOException;
@@ -22,7 +25,7 @@ public class RustWriter implements AutoCloseable {
public static void writeTo(Path path, Write write) throws IOException {
CodeWriter.writeTo(
path,
- LINE_COMMENT_START,
+ CONFIG,
writer -> write.write(new RustWriter(writer))
);
}
@@ -30,11 +33,15 @@ public class RustWriter implements AutoCloseable {
public static void writeTo(CodeWriter.CodeWriterFile file, Write write) throws IOException {
CodeWriter.writeTo(
file,
- LINE_COMMENT_START,
+ CONFIG,
writer -> write.write(new RustWriter(writer))
);
}
+ public static Stripper stripper(Path outputPath) {
+ return CodeWriter.stripper(outputPath, CONFIG);
+ }
+
private final CodeWriter writer;
public RustWriter(CodeWriter writer) {
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/SqlWriter.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/SqlWriter.java
index b6edc1b..ef1562e 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/SqlWriter.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/SqlWriter.java
@@ -1,6 +1,7 @@
package org.zwobble.hobgoblin.compiler.output.lang.sql;
import org.zwobble.hobgoblin.compiler.output.CodeWriter;
+import org.zwobble.hobgoblin.compiler.output.generators.Stripper;
import org.zwobble.hobgoblin.compiler.output.lang.sql.ast.*;
import java.io.IOException;
@@ -10,6 +11,8 @@ import static org.zwobble.hobgoblin.compiler.output.CodeWriter.writeWithSeparato
public class SqlWriter {
private static final String LINE_COMMENT_START = "--";
+ private static final CodeWriter.CodeWriterConfig CONFIG =
+ new CodeWriter.CodeWriterConfig(LINE_COMMENT_START);
public interface Write {
void write(SqlWriter writer) throws IOException;
@@ -18,7 +21,7 @@ public class SqlWriter {
public static void writeTo(Path path, Write write) throws IOException {
CodeWriter.writeTo(
path,
- LINE_COMMENT_START,
+ CONFIG,
writer -> write.write(new SqlWriter(writer))
);
}
@@ -26,11 +29,15 @@ public class SqlWriter {
public static void writeTo(CodeWriter.CodeWriterFile file, Write write) throws IOException {
CodeWriter.writeTo(
file,
- LINE_COMMENT_START,
+ CONFIG,
writer -> write.write(new SqlWriter(writer))
);
}
+ public static Stripper stripper(Path outputPath) {
+ return CodeWriter.stripper(outputPath, CONFIG);
+ }
+
private final CodeWriter writer;
public SqlWriter(CodeWriter writer) {
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/typescript/TypescriptWriter.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/typescript/TypescriptWriter.java
index 3d5d99f..72e9cf5 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/typescript/TypescriptWriter.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/typescript/TypescriptWriter.java
@@ -2,6 +2,7 @@ package org.zwobble.hobgoblin.compiler.output.lang.typescript;
import org.zwobble.hobgoblin.compiler.ast.DocComment;
import org.zwobble.hobgoblin.compiler.output.CodeWriter;
+import org.zwobble.hobgoblin.compiler.output.generators.Stripper;
import org.zwobble.hobgoblin.compiler.output.lang.typescript.ast.*;
import java.io.IOException;
@@ -11,6 +12,8 @@ import static org.zwobble.hobgoblin.compiler.output.CodeWriter.writeWithSeparato
public class TypescriptWriter implements AutoCloseable {
private static final String LINE_COMMENT_START = "//";
+ private static final CodeWriter.CodeWriterConfig CONFIG =
+ new CodeWriter.CodeWriterConfig(LINE_COMMENT_START);
public interface Write {
void write(TypescriptWriter writer) throws IOException;
@@ -19,7 +22,7 @@ public class TypescriptWriter implements AutoCloseable {
public static void writeTo(Path path, Write write) throws IOException {
CodeWriter.writeTo(
path,
- LINE_COMMENT_START,
+ CONFIG,
writer -> write.write(new TypescriptWriter(writer))
);
}
@@ -27,11 +30,15 @@ public class TypescriptWriter implements AutoCloseable {
public static void writeTo(CodeWriter.CodeWriterFile file, Write write) throws IOException {
CodeWriter.writeTo(
file,
- LINE_COMMENT_START,
+ CONFIG,
writer -> write.write(new TypescriptWriter(writer))
);
}
+ public static Stripper stripper(Path outputPath) {
+ return CodeWriter.stripper(outputPath, CONFIG);
+ }
+
private final CodeWriter writer;
public TypescriptWriter(CodeWriter writer) {
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/parser/OperationParser.java b/src/main/java/org/zwobble/hobgoblin/compiler/parser/OperationParser.java
new file mode 100644
index 0000000..27c2740
--- /dev/null
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/parser/OperationParser.java
@@ -0,0 +1,15 @@
+package org.zwobble.hobgoblin.compiler.parser;
+
+import org.zwobble.sourcetext.SourcePosition;
+
+import java.util.List;
+
+interface OperationParser<TOperatorPrecedence, TNode> {
+ TOperatorPrecedence precedence();
+ List<TokenType> operatorTokenTypes();
+ TNode parse(
+ SourcePosition start,
+ TNode left,
+ TokenIterator tokens
+ );
+}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/parser/OperatorPrecedence.java b/src/main/java/org/zwobble/hobgoblin/compiler/parser/OperatorPrecedence.java
new file mode 100644
index 0000000..b63ca86
--- /dev/null
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/parser/OperatorPrecedence.java
@@ -0,0 +1,5 @@
+package org.zwobble.hobgoblin.compiler.parser;
+
+enum OperatorPrecedence {
+ CALL,
+}
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 3563d0a..cdeeedd 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/parser/Parser.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/parser/Parser.java
@@ -11,9 +11,12 @@ import org.zwobble.sourcetext.SourceText;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import java.util.Optional;
import java.util.function.BooleanSupplier;
import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
public class Parser {
private Parser() {
@@ -113,6 +116,8 @@ public class Parser {
return parseEnumDefinition(tokens, docComment);
} else if (tokens.isNext(TokenType.KEYWORD_NATIVE)) {
return parseNativeTypeDefinition(tokens, docComment);
+ } else if (tokens.isNext(TokenType.IDENTIFIER, "query")) {
+ return parseQueryDefinition(tokens, docComment);
} else if (tokens.isNext(TokenType.KEYWORD_STRUCT)) {
return parseStructDefinition(tokens, docComment);
} else if (tokens.isNext(TokenType.KEYWORD_SUM)) {
@@ -239,6 +244,43 @@ public class Parser {
return new DocComment(docComment.toString());
}
+ private static UntypedQueryDefinitionNode parseQueryDefinition(
+ TokenIterator tokens,
+ DocComment docComment
+ ) {
+ var start = tokens.startPosition();
+
+ tokens.skip(TokenType.IDENTIFIER, "query");
+ var name = parseIdentifier(tokens);
+
+ tokens.skip(TokenType.SYMBOL_PAREN_OPEN);
+ tokens.skip(TokenType.SYMBOL_PAREN_CLOSE);
+
+ tokens.skip(TokenType.IDENTIFIER, "on");
+ var databaseSchema = parseTypeLevelExpression(tokens);
+
+ tokens.skip(TokenType.SYMBOL_BRACE_OPEN);
+
+ var statements = parseMany(
+ () -> tokens.isNext(TokenType.SYMBOL_BRACE_CLOSE),
+ () -> parseStatement(tokens),
+ () -> true
+ );
+
+ tokens.skip(TokenType.SYMBOL_BRACE_CLOSE);
+
+ var end = tokens.endPosition();
+ var source = createSource(start, end);
+
+ return new UntypedQueryDefinitionNode(
+ name,
+ databaseSchema,
+ statements,
+ docComment,
+ source
+ );
+ }
+
private static UntypedStructDefinitionNode parseStructDefinition(
TokenIterator tokens,
DocComment docComment
@@ -415,6 +457,19 @@ public class Parser {
return Optional.of(typeParams);
}
+ // == Params ==
+
+ private static UntypedParamNode parseParam(TokenIterator tokens) {
+ var start = tokens.startPosition();
+
+ var name = parseIdentifier(tokens);
+
+ var end = tokens.endPosition();
+ var source = createSource(start, end);
+
+ return new UntypedParamNode(name, source);
+ }
+
// == Type-level expressions ==
static UntypedTypeLevelExpressionNode parseTypeLevelExpression(
@@ -455,6 +510,176 @@ public class Parser {
);
}
+ // == Statements ==
+
+ static UntypedStatementNode parseStatement(TokenIterator tokens) {
+ if (tokens.isNext(TokenType.IDENTIFIER, "return")) {
+ return parseReturn(tokens);
+ } else {
+ throw new UnsupportedOperationException("TODO");
+ }
+ }
+
+ private static UntypedReturnNode parseReturn(TokenIterator tokens) {
+ var start = tokens.startPosition();
+
+ tokens.skip(TokenType.IDENTIFIER, "return");
+ var expression = parseTopLevelExpression(tokens);
+ tokens.skip(TokenType.SYMBOL_SEMICOLON);
+
+ var end = tokens.endPosition();
+ var source = createSource(start, end);
+
+ return new UntypedReturnNode(expression, source);
+ }
+
+ // == Expressions ==
+
+ static UntypedExpressionNode parseTopLevelExpression(TokenIterator tokens) {
+ return parseExpression(tokens, Optional.empty());
+ }
+
+ private static UntypedExpressionNode parseExpression(
+ TokenIterator tokens,
+ Optional<OperatorPrecedence> parentPrecedence
+ ) {
+ var start = tokens.startPosition();
+ var left = parsePrimaryExpression(tokens);
+
+ while (true) {
+ var operationParser = OPERATION_PARSERS.get(tokens.peek().tokenType());
+ if (operationParser == null || parentPrecedence.isPresent() && operationParser.precedence().ordinal() <= parentPrecedence.get().ordinal()) {
+ return left;
+ }
+ left = operationParser.parse(start, left, tokens);
+ }
+ }
+
+ private static UntypedExpressionNode parsePrimaryExpression(
+ TokenIterator tokens
+ ) {
+ if (tokens.isNext(TokenType.SYMBOL_DOLLAR)) {
+ return parseFunctionExpression(tokens);
+ } else if (tokens.isNext(TokenType.IDENTIFIER)) {
+ return parseReference(tokens);
+ } else {
+ throw new UnsupportedOperationException("TODO");
+ }
+ }
+
+ private static UntypedFunctionExpressionNode parseFunctionExpression(TokenIterator tokens) {
+ var start = tokens.startPosition();
+
+ tokens.skip(TokenType.SYMBOL_DOLLAR);
+ tokens.skip(TokenType.SYMBOL_PAREN_OPEN);
+
+ var params = parseMany(
+ () -> tokens.isNext(TokenType.SYMBOL_PAREN_CLOSE),
+ () -> parseParam(tokens),
+ () -> tokens.trySkip(TokenType.SYMBOL_COMMA)
+ );
+
+ tokens.skip(TokenType.SYMBOL_PAREN_CLOSE);
+ tokens.skip(TokenType.SYMBOL_FAT_ARROW);
+
+ var body = parseTopLevelExpression(tokens);
+
+ var end = tokens.endPosition();
+ var source = createSource(start, end);
+
+ return new UntypedFunctionExpressionNode(
+ params,
+ body,
+ source
+ );
+ }
+
+ private static UntypedReferenceNode parseReference(TokenIterator tokens) {
+ var start = tokens.startPosition();
+
+ var name = parseIdentifier(tokens);
+
+ var end = tokens.endPosition();
+ var source = createSource(start, end);
+
+ return new UntypedReferenceNode(name, source);
+ }
+
+ private static final OperationParser<OperatorPrecedence, UntypedExpressionNode> CALL_PARSER = new OperationParser<>() {
+ @Override
+ public OperatorPrecedence precedence() {
+ return OperatorPrecedence.CALL;
+ }
+
+ @Override
+ public List<TokenType> operatorTokenTypes() {
+ return List.of(TokenType.SYMBOL_PAREN_OPEN);
+ }
+
+ @Override
+ public UntypedExpressionNode parse(
+ SourcePosition start,
+ UntypedExpressionNode left,
+ TokenIterator tokens
+ ) {
+ tokens.skip(TokenType.SYMBOL_PAREN_OPEN);
+
+ var args = parseMany(
+ () -> tokens.isNext(TokenType.SYMBOL_PAREN_CLOSE),
+ () -> parseTopLevelExpression(tokens),
+ () -> tokens.trySkip(TokenType.SYMBOL_COMMA)
+ );
+
+ tokens.skip(TokenType.SYMBOL_PAREN_CLOSE);
+
+ var end = tokens.endPosition();
+ var source = createSource(start, end);
+
+ return new UntypedCallNode(left, args, source);
+ }
+ };
+
+ private static final OperationParser<OperatorPrecedence, UntypedExpressionNode> MEMBER_ACCESS_PARSER = new OperationParser<>() {
+ @Override
+ public OperatorPrecedence precedence() {
+ return OperatorPrecedence.CALL;
+ }
+
+ @Override
+ public List<TokenType> operatorTokenTypes() {
+ return List.of(TokenType.SYMBOL_DOT);
+ }
+
+ @Override
+ public UntypedExpressionNode parse(
+ SourcePosition start,
+ UntypedExpressionNode left,
+ TokenIterator tokens
+ ) {
+ tokens.skip(TokenType.SYMBOL_DOT);
+ var fieldName = parseIdentifier(tokens);
+
+ var end = tokens.endPosition();
+ var source = createSource(start, end);
+
+ return new UntypedMemberAccessNode(left, fieldName, source);
+ }
+ };
+
+ private static final Map<TokenType, OperationParser<OperatorPrecedence, UntypedExpressionNode>> OPERATION_PARSERS = Stream.of(
+ CALL_PARSER,
+ MEMBER_ACCESS_PARSER
+ )
+ .flatMap(parser ->
+ parser.operatorTokenTypes().stream().map(tokenType -> Map.entry(tokenType, parser))
+ )
+ .collect(Collectors.toMap(
+ x -> x.getKey(),
+ x -> x.getValue()
+ ));
+
+ // == Qualified type names ==
+
public static QualifiedTypeName parseQualifiedTypeName(SourceText sourceText) {
var tokens = Tokenizer.tokenize(sourceText);
var tokenIterator = tokens.iterator();
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/parser/TokenType.java b/src/main/java/org/zwobble/hobgoblin/compiler/parser/TokenType.java
index 2a85072..1181fca 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/parser/TokenType.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/parser/TokenType.java
@@ -19,8 +19,10 @@ enum TokenType {
SYMBOL_BRACE_CLOSE,
SYMBOL_COLON,
SYMBOL_COMMA,
+ SYMBOL_DOLLAR,
SYMBOL_DOT,
SYMBOL_DOT_DOT,
+ SYMBOL_FAT_ARROW,
SYMBOL_FORWARD_SLASH,
SYMBOL_PAREN_OPEN,
SYMBOL_PAREN_CLOSE,
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/parser/Tokenizer.java b/src/main/java/org/zwobble/hobgoblin/compiler/parser/Tokenizer.java
index 1a775b0..56c2123 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/parser/Tokenizer.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/parser/Tokenizer.java
@@ -154,6 +154,10 @@ class Tokenizer {
tokenType = TokenType.SYMBOL_DOT_DOT;
iterator.skip();
iterator.skip();
+ } else if ("=>".contentEquals(iterator.peekSequence(2))) {
+ tokenType = TokenType.SYMBOL_FAT_ARROW;
+ iterator.skip();
+ iterator.skip();
} else {
switch (iterator.peek()) {
case '{':
@@ -176,6 +180,11 @@ class Tokenizer {
iterator.skip();
break;
+ case '$':
+ tokenType = TokenType.SYMBOL_DOLLAR;
+ iterator.skip();
+ break;
+
case '.':
tokenType = TokenType.SYMBOL_DOT;
iterator.skip();
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 c8dfc05..32acc82 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java
@@ -9,6 +9,7 @@ import org.zwobble.hobgoblin.compiler.typechecker.errors.NoSuchFieldError;
import org.zwobble.hobgoblin.compiler.types.*;
import java.util.ArrayList;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@@ -21,6 +22,8 @@ public class TypeChecker {
private TypeChecker() {
}
+ // == Namespaces ==
+
public static List<TypedNamespaceNode> typeCheckNamespaces(
List<UntypedNamespaceNode> untypedNamespaces,
TypeCheckerGlobalContext context
@@ -89,13 +92,18 @@ public class TypeChecker {
return typedNamespaceNodes;
}
+ // == Namespace statements ==
+
static Optional<Type> declareNamespaceStatement(
UntypedNamespaceStatementNode untyped,
TypeCheckerNamespaceContext context
) {
return switch (untyped) {
- case UntypedDatabaseSchemaDefinitionNode _ ->
- Optional.empty();
+ case UntypedDatabaseSchemaDefinitionNode untypedDatabaseSchemaDefinition ->
+ Optional.of(declareDatabaseSchemaDefinition(
+ untypedDatabaseSchemaDefinition,
+ context
+ ));
case UntypedEnumDefinitionNode untypedEnumDefinitionNode ->
Optional.of(declareEnumDefinitionNode(untyped, context));
@@ -103,6 +111,9 @@ public class TypeChecker {
case UntypedNativeTypeDefinitionNode untypedNativeTypeDefinition ->
Optional.of(declareNativeTypeDefinition(untypedNativeTypeDefinition, context));
+ case UntypedQueryDefinitionNode _ ->
+ Optional.empty();
+
case UntypedStructDefinitionNode untypedStructDefinition ->
Optional.of(declareStructDefinition(untypedStructDefinition, context));
@@ -125,6 +136,9 @@ public class TypeChecker {
case UntypedNativeTypeDefinitionNode untypedNativeTypeDefinition ->
defineNativeTypeDefinition(untypedNativeTypeDefinition, context);
+ case UntypedQueryDefinitionNode untypedQueryDefinition ->
+ defineQueryDefinition(untypedQueryDefinition, context);
+
case UntypedStructDefinitionNode untypedStructDefinition ->
defineStructDefinition(untypedStructDefinition, context);
@@ -133,15 +147,36 @@ public class TypeChecker {
};
}
+ private static Type declareDatabaseSchemaDefinition(
+ UntypedDatabaseSchemaDefinitionNode untyped,
+ TypeCheckerNamespaceContext context
+ ) {
+ var databaseSchema = new DatabaseSchema(context.namespaceName(), untyped.name());
+ var type = Types.databaseSchema(databaseSchema);
+
+ context.declare(untyped.name(), type, untyped.source());
+
+ return type;
+ }
+
private static TypedNamespaceStatementNode defineDatabaseSchemaDefinition(
UntypedDatabaseSchemaDefinitionNode untyped,
TypeCheckerNamespaceContext context
) {
+ var databaseSchemaInfo = new DatabaseSchemaInfo(new LinkedHashMap<>());
+
+ var typedBody = untyped.body().stream()
+ .map(statement -> typeCheckDatabaseSchemaStatement(statement, databaseSchemaInfo, context))
+ .toList();
+
+ context.defineDatabaseSchema(
+ new DatabaseSchema(context.namespaceName(), untyped.name()),
+ databaseSchemaInfo
+ );
+
return new TypedDatabaseSchemaDefinitionNode(
untyped.name(),
- untyped.body().stream()
- .map(statement -> typeCheckDatabaseSchemaStatement(statement, context))
- .toList(),
+ typedBody,
untyped.docComment(),
untyped.source()
);
@@ -247,6 +282,21 @@ public class TypeChecker {
return metaType;
}
+ private static TypedQueryDefinitionNode defineQueryDefinition(
+ UntypedQueryDefinitionNode untyped,
+ TypeCheckerNamespaceContext context
+ ) {
+ var value = evalStatements(untyped.statements(), context);
+ var table = (Table) value;
+
+ return new TypedQueryDefinitionNode(
+ untyped.name(),
+ table,
+ untyped.docComment(),
+ untyped.source()
+ );
+ }
+
private static TypedStructDefinitionNode defineStructDefinition(
UntypedStructDefinitionNode untyped,
TypeCheckerNamespaceContext context
@@ -455,18 +505,22 @@ public class TypeChecker {
}
}
+ // == Database schema statements ==
+
static TypedDatabaseSchemaStatementNode typeCheckDatabaseSchemaStatement(
UntypedDatabaseSchemaStatementNode statement,
+ DatabaseSchemaInfo databaseSchemaInfo,
TypeCheckerNamespaceContext context
) {
return switch (statement) {
case UntypedTableDefinitionNode untypedTableDefinition ->
- typeCheckTableDefinition(untypedTableDefinition, context);
+ typeCheckTableDefinition(untypedTableDefinition, databaseSchemaInfo, context);
};
}
private static TypedTableDefinitionNode typeCheckTableDefinition(
UntypedTableDefinitionNode untyped,
+ DatabaseSchemaInfo databaseSchemaInfo,
TypeCheckerNamespaceContext context
) {
var rowTypeTypedNode = typeCheckMetaType(untyped.rowType(), context);
@@ -488,6 +542,10 @@ public class TypeChecker {
throw new NoSuchFieldError(rowType, untyped.primaryKey(), untyped.source());
}
+ var tableInfo = new TableInfo(rowType, primaryKeyField.get());
+
+ databaseSchemaInfo.tables().put(untyped.name(), tableInfo);
+
return new TypedTableDefinitionNode(
untyped.name(),
rowType,
@@ -497,6 +555,8 @@ public class TypeChecker {
);
}
+ // == Type-level expressions ==
+
static TypedTypeLevelExpressionNode<? extends TypeLevelValue> typeCheckTypeLevelExpression(
UntypedTypeLevelExpressionNode untyped,
TypeCheckerNamespaceContext context
@@ -602,4 +662,44 @@ public class TypeChecker {
);
}
}
+
+ // == Statements ==
+
+ private static TypeLevelValue evalStatements(
+ List<UntypedStatementNode> statements,
+ TypeCheckerNamespaceContext context
+ ) {
+ for (var statement : statements) {
+ switch (statement) {
+ case UntypedReturnNode untypedReturn -> {
+ // TODO: test multiple returns.
+ return evalExpression(untypedReturn.expression(), context);
+ }
+ }
+ }
+
+ throw new UnsupportedOperationException("TODO");
+ }
+
+ // == Expressions ==
+
+ private static TypeLevelValue evalExpression(
+ UntypedExpressionNode expression,
+ TypeCheckerNamespaceContext context
+ ) {
+ switch (expression) {
+ case UntypedCallNode _ -> {
+ throw new UnsupportedOperationException("TODO");
+ }
+ case UntypedFunctionExpressionNode _ -> {
+ throw new UnsupportedOperationException("TODO");
+ }
+ case UntypedMemberAccessNode _ -> {
+ throw new UnsupportedOperationException("TODO");
+ }
+ case UntypedReferenceNode reference -> {
+ return lookupTypeLevelValue(reference.name(), reference.source(), context);
+ }
+ }
+ }
}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerNamespaceContext.java b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerNamespaceContext.java
index ce7153f..b18769d 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerNamespaceContext.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerNamespaceContext.java
@@ -57,6 +57,13 @@ public class TypeCheckerNamespaceContext {
return Optional.ofNullable(this.variables.get(name));
}
+ public void defineDatabaseSchema(
+ DatabaseSchema databaseSchema,
+ DatabaseSchemaInfo databaseSchemaInfo
+ ) {
+ this.typesInfo.defineDatabaseSchema(databaseSchema, databaseSchemaInfo);
+ }
+
public void defineEnumType(EnumType enumType, List<EnumVariant> enumVariants) {
this.typesInfo.defineEnumType(enumType, enumVariants);
}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypesInfo.java b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypesInfo.java
index d13d2c6..e05ddc3 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypesInfo.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypesInfo.java
@@ -8,6 +8,8 @@ import java.util.Optional;
public interface TypesInfo {
TypesInfo EMPTY = TypesInfoInMemory.empty();
+ DatabaseSchemaInfo databaseSchemaInfo(DatabaseSchema databaseSchema);
+
boolean isDefined(SimpleStructType type);
Optional<List<Field>> fieldsOf(SimpleStructType structType);
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypesInfoInMemory.java b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypesInfoInMemory.java
index 67d5c3b..011b7e5 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypesInfoInMemory.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypesInfoInMemory.java
@@ -11,10 +11,13 @@ public class TypesInfoInMemory implements TypesInfo {
new HashMap<>(),
new HashMap<>(),
new HashMap<>(),
+ new HashMap<>(),
new HashMap<>()
);
}
+ private final Map<DatabaseSchema, DatabaseSchemaInfo> databaseSchemaInfo;
+
private final Map<EnumType, List<EnumVariant>> enumVariants;
private final Map<Type, Optional<List<Field>>> structFields;
@@ -23,17 +26,37 @@ public class TypesInfoInMemory implements TypesInfo {
private final Map<SimpleStructType, List<SumType>> variantToSums;
private TypesInfoInMemory(
+ Map<DatabaseSchema, DatabaseSchemaInfo> databaseSchemaInfo,
Map<EnumType, List<EnumVariant>> enumVariants,
Map<Type, Optional<List<Field>>> structFields,
Map<SumType, SumTypeInfo> sumTypeInfos,
Map<SimpleStructType, List<SumType>> variantToSums
) {
+ this.databaseSchemaInfo = databaseSchemaInfo;
this.enumVariants = enumVariants;
this.structFields = structFields;
this.sumTypeInfos = sumTypeInfos;
this.variantToSums = variantToSums;
}
+ public void defineDatabaseSchema(
+ DatabaseSchema databaseSchema,
+ DatabaseSchemaInfo databaseSchemaInfo
+ ) {
+ this.databaseSchemaInfo.put(databaseSchema, databaseSchemaInfo);
+ }
+
+ @Override
+ public DatabaseSchemaInfo databaseSchemaInfo(DatabaseSchema databaseSchema) {
+ var info = this.databaseSchemaInfo.get(databaseSchema);
+ if (info == null) {
+ // TODO: better error
+ throw new UnsupportedOperationException("TODO");
+ } else {
+ return info;
+ }
+ }
+
public void defineEnumType(EnumType enumType, List<EnumVariant> enumVariants) {
this.enumVariants.put(enumType, enumVariants);
}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/types/DatabaseSchema.java b/src/main/java/org/zwobble/hobgoblin/compiler/types/DatabaseSchema.java
new file mode 100644
index 0000000..e57d587
--- /dev/null
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/types/DatabaseSchema.java
@@ -0,0 +1,8 @@
+package org.zwobble.hobgoblin.compiler.types;
+
+public record DatabaseSchema(NamespaceName namespaceName, String name) implements TypeLevelValue {
+ @Override
+ public String describe() {
+ return namespaceName.toString() + "." + name;
+ }
+}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/types/DatabaseSchemaInfo.java b/src/main/java/org/zwobble/hobgoblin/compiler/types/DatabaseSchemaInfo.java
new file mode 100644
index 0000000..5ba5712
--- /dev/null
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/types/DatabaseSchemaInfo.java
@@ -0,0 +1,6 @@
+package org.zwobble.hobgoblin.compiler.types;
+
+import java.util.SequencedMap;
+
+public record DatabaseSchemaInfo(SequencedMap<String, TableInfo> tables) {
+}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/types/HobgoblinNativeTypes.java b/src/main/java/org/zwobble/hobgoblin/compiler/types/HobgoblinNativeTypes.java
index 96efbd2..186557e 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/types/HobgoblinNativeTypes.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/types/HobgoblinNativeTypes.java
@@ -40,4 +40,12 @@ public class HobgoblinNativeTypes {
public static Field arbitraryField() {
return new Field("", arbitraryType(), NullSource.INSTANCE);
}
+
+ public static DatabaseSchema arbitraryDatabaseSchema() {
+ return new DatabaseSchema(arbitraryNamespaceName(), "");
+ }
+
+ public static Table arbitraryTable() {
+ return new Table(arbitraryDatabaseSchema(), "");
+ }
}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/types/Table.java b/src/main/java/org/zwobble/hobgoblin/compiler/types/Table.java
new file mode 100644
index 0000000..a33e226
--- /dev/null
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/types/Table.java
@@ -0,0 +1,8 @@
+package org.zwobble.hobgoblin.compiler.types;
+
+public record Table(DatabaseSchema databaseSchema, String name) implements TypeLevelValue {
+ @Override
+ public String describe() {
+ return databaseSchema.describe() + "." + name;
+ }
+}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/types/TableInfo.java b/src/main/java/org/zwobble/hobgoblin/compiler/types/TableInfo.java
new file mode 100644
index 0000000..6632e51
--- /dev/null
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/types/TableInfo.java
@@ -0,0 +1,7 @@
+package org.zwobble.hobgoblin.compiler.types;
+
+public record TableInfo(
+ SimpleStructType rowType,
+ Field primaryKey
+) {
+}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/types/TypeLevelValue.java b/src/main/java/org/zwobble/hobgoblin/compiler/types/TypeLevelValue.java
index cf62eb1..8d12c2e 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/types/TypeLevelValue.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/types/TypeLevelValue.java
@@ -1,5 +1,5 @@
package org.zwobble.hobgoblin.compiler.types;
-public sealed interface TypeLevelValue permits Type, TypeConstructor {
+public sealed interface TypeLevelValue permits DatabaseSchema, Table, Type, TypeConstructor {
String describe();
}
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/types/Types.java b/src/main/java/org/zwobble/hobgoblin/compiler/types/Types.java
index cfbb5ba..0d321a0 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/types/Types.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/types/Types.java
@@ -26,4 +26,12 @@ public class Types {
public static Type metaType(TypeConstructor<?> constructor) {
return new TypeLevelValueType(constructor);
}
+
+ public static Type databaseSchema(DatabaseSchema databaseSchema) {
+ return new TypeLevelValueType(databaseSchema);
+ }
+
+ public static Type table(Table table) {
+ return new TypeLevelValueType(table);
+ }
}
diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/ExampleTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/ExampleTests.java
index dbd1227..d1f177d 100644
--- a/src/test/java/org/zwobble/hobgoblin/compiler/ExampleTests.java
+++ b/src/test/java/org/zwobble/hobgoblin/compiler/ExampleTests.java
@@ -32,6 +32,7 @@ public class ExampleTests {
var javaOutputPath = verifyJavaOutput(exampleSet);
var rustOutputPath = verifyRustOutput(exampleSet);
+ verifySqlite3Output(exampleSet);
verifyTypescriptOutput(exampleSet);
var transient0OutputDirs = Stream.of(javaOutputPath, rustOutputPath)
@@ -68,6 +69,18 @@ public class ExampleTests {
return verifyOutput(exampleSet, "rust", List.of(List.of("cargo", "test")));
}
+ private void verifySqlite3Output(
+ ExampleSet exampleSet
+ ) throws NoSuchAlgorithmException, IOException, InterruptedException {
+ verifyOutput(
+ exampleSet,
+ "sqlite3",
+ List.of(
+ List.of("python3", "-m", "unittest", "test.py")
+ )
+ );
+ }
+
private Optional<Path> verifyTypescriptOutput(ExampleSet exampleSet) throws NoSuchAlgorithmException, IOException, InterruptedException {
return verifyOutput(exampleSet, "typescript", List.of(
List.of("pnpm", "install"),
diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/ast/typed/TypedQueryDefinitionNodeMatcher.java b/src/test/java/org/zwobble/hobgoblin/compiler/ast/typed/TypedQueryDefinitionNodeMatcher.java
new file mode 100644
index 0000000..651ede0
--- /dev/null
+++ b/src/test/java/org/zwobble/hobgoblin/compiler/ast/typed/TypedQueryDefinitionNodeMatcher.java
@@ -0,0 +1,59 @@
+// Generated by hobgoblin.
+
+package org.zwobble.hobgoblin.compiler.ast.typed;
+
+// Custom area start: org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNodeMatcher imports
+// Custom area end: org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNodeMatcher imports
+
+public final class TypedQueryDefinitionNodeMatcher implements org.zwobble.precisely.Matcher<java.lang.Object> {
+ public static org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNodeMatcher isTypedQueryDefinitionNode() {
+ return new org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNodeMatcher(java.util.List.of());
+ }
+
+ private final java.util.List<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode>> submatchers;
+
+ private TypedQueryDefinitionNodeMatcher(
+ java.util.List<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode>> 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.typed.TypedQueryDefinitionNode.class, this.submatchers);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNodeMatcher withName(org.zwobble.precisely.Matcher<? super String> name) {
+ var submatchers = new java.util.ArrayList<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode>>(this.submatchers);
+ submatchers.add(org.zwobble.precisely.Matchers.has("name", org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode::name, (org.zwobble.precisely.Matcher) name));
+ return new org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNodeMatcher(submatchers);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNodeMatcher withTable(org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.types.Table> table) {
+ var submatchers = new java.util.ArrayList<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode>>(this.submatchers);
+ submatchers.add(org.zwobble.precisely.Matchers.has("table", org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode::table, (org.zwobble.precisely.Matcher) table));
+ return new org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNodeMatcher(submatchers);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNodeMatcher 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.typed.TypedQueryDefinitionNode>>(this.submatchers);
+ submatchers.add(org.zwobble.precisely.Matchers.has("docComment", org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode::docComment, (org.zwobble.precisely.Matcher) docComment));
+ return new org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNodeMatcher(submatchers);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNodeMatcher 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.typed.TypedQueryDefinitionNode>>(this.submatchers);
+ submatchers.add(org.zwobble.precisely.Matchers.has("source", org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode::source, (org.zwobble.precisely.Matcher) source));
+ return new org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNodeMatcher(submatchers);
+ }
+
+ // Custom area start: org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNodeMatcher body
+ // Custom area end: org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNodeMatcher body
+}
diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedCallNodeMatcher.java b/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedCallNodeMatcher.java
new file mode 100644
index 0000000..a9ce6a5
--- /dev/null
+++ b/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedCallNodeMatcher.java
@@ -0,0 +1,53 @@
+// Generated by hobgoblin.
+
+package org.zwobble.hobgoblin.compiler.ast.untyped;
+
+// Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNodeMatcher imports
+// Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNodeMatcher imports
+
+public final class UntypedCallNodeMatcher implements org.zwobble.precisely.Matcher<java.lang.Object> {
+ public static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNodeMatcher isUntypedCallNode() {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNodeMatcher(java.util.List.of());
+ }
+
+ private final java.util.List<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNode>> submatchers;
+
+ private UntypedCallNodeMatcher(
+ java.util.List<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNode>> 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.UntypedCallNode.class, this.submatchers);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNodeMatcher withReceiver(org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode> receiver) {
+ var submatchers = new java.util.ArrayList<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNode>>(this.submatchers);
+ submatchers.add(org.zwobble.precisely.Matchers.has("receiver", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNode::receiver, (org.zwobble.precisely.Matcher) receiver));
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNodeMatcher(submatchers);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNodeMatcher withArgs(org.zwobble.precisely.Matcher<? super java.util.List<org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode>> args) {
+ var submatchers = new java.util.ArrayList<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNode>>(this.submatchers);
+ submatchers.add(org.zwobble.precisely.Matchers.has("args", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNode::args, (org.zwobble.precisely.Matcher) args));
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNodeMatcher(submatchers);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNodeMatcher 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.UntypedCallNode>>(this.submatchers);
+ submatchers.add(org.zwobble.precisely.Matchers.has("source", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNode::source, (org.zwobble.precisely.Matcher) source));
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNodeMatcher(submatchers);
+ }
+
+ // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNodeMatcher body
+ // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNodeMatcher body
+}
diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedFunctionExpressionNodeMatcher.java b/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedFunctionExpressionNodeMatcher.java
new file mode 100644
index 0000000..71356e8
--- /dev/null
+++ b/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedFunctionExpressionNodeMatcher.java
@@ -0,0 +1,53 @@
+// Generated by hobgoblin.
+
+package org.zwobble.hobgoblin.compiler.ast.untyped;
+
+// Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNodeMatcher imports
+// Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNodeMatcher imports
+
+public final class UntypedFunctionExpressionNodeMatcher implements org.zwobble.precisely.Matcher<java.lang.Object> {
+ public static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNodeMatcher isUntypedFunctionExpressionNode() {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNodeMatcher(java.util.List.of());
+ }
+
+ private final java.util.List<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNode>> submatchers;
+
+ private UntypedFunctionExpressionNodeMatcher(
+ java.util.List<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNode>> 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.UntypedFunctionExpressionNode.class, this.submatchers);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNodeMatcher withParams(org.zwobble.precisely.Matcher<? super java.util.List<org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNode>> params) {
+ var submatchers = new java.util.ArrayList<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNode>>(this.submatchers);
+ submatchers.add(org.zwobble.precisely.Matchers.has("params", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNode::params, (org.zwobble.precisely.Matcher) params));
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNodeMatcher(submatchers);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNodeMatcher withBody(org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode> body) {
+ var submatchers = new java.util.ArrayList<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNode>>(this.submatchers);
+ submatchers.add(org.zwobble.precisely.Matchers.has("body", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNode::body, (org.zwobble.precisely.Matcher) body));
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNodeMatcher(submatchers);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNodeMatcher 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.UntypedFunctionExpressionNode>>(this.submatchers);
+ submatchers.add(org.zwobble.precisely.Matchers.has("source", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNode::source, (org.zwobble.precisely.Matcher) source));
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNodeMatcher(submatchers);
+ }
+
+ // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNodeMatcher body
+ // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNodeMatcher body
+}
diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedMemberAccessNodeMatcher.java b/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedMemberAccessNodeMatcher.java
new file mode 100644
index 0000000..ffe9804
--- /dev/null
+++ b/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedMemberAccessNodeMatcher.java
@@ -0,0 +1,53 @@
+// Generated by hobgoblin.
+
+package org.zwobble.hobgoblin.compiler.ast.untyped;
+
+// Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNodeMatcher imports
+// Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNodeMatcher imports
+
+public final class UntypedMemberAccessNodeMatcher implements org.zwobble.precisely.Matcher<java.lang.Object> {
+ public static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNodeMatcher isUntypedMemberAccessNode() {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNodeMatcher(java.util.List.of());
+ }
+
+ private final java.util.List<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNode>> submatchers;
+
+ private UntypedMemberAccessNodeMatcher(
+ java.util.List<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNode>> 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.UntypedMemberAccessNode.class, this.submatchers);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNodeMatcher withReceiver(org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode> receiver) {
+ var submatchers = new java.util.ArrayList<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNode>>(this.submatchers);
+ submatchers.add(org.zwobble.precisely.Matchers.has("receiver", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNode::receiver, (org.zwobble.precisely.Matcher) receiver));
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNodeMatcher(submatchers);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNodeMatcher withFieldName(org.zwobble.precisely.Matcher<? super String> fieldName) {
+ var submatchers = new java.util.ArrayList<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNode>>(this.submatchers);
+ submatchers.add(org.zwobble.precisely.Matchers.has("fieldName", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNode::fieldName, (org.zwobble.precisely.Matcher) fieldName));
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNodeMatcher(submatchers);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNodeMatcher 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.UntypedMemberAccessNode>>(this.submatchers);
+ submatchers.add(org.zwobble.precisely.Matchers.has("source", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNode::source, (org.zwobble.precisely.Matcher) source));
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNodeMatcher(submatchers);
+ }
+
+ // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNodeMatcher body
+ // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNodeMatcher body
+}
diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedParamNodeMatcher.java b/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedParamNodeMatcher.java
new file mode 100644
index 0000000..c140fb2
--- /dev/null
+++ b/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedParamNodeMatcher.java
@@ -0,0 +1,47 @@
+// Generated by hobgoblin.
+
+package org.zwobble.hobgoblin.compiler.ast.untyped;
+
+// Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNodeMatcher imports
+// Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNodeMatcher imports
+
+public final class UntypedParamNodeMatcher implements org.zwobble.precisely.Matcher<java.lang.Object> {
+ public static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNodeMatcher isUntypedParamNode() {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNodeMatcher(java.util.List.of());
+ }
+
+ private final java.util.List<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNode>> submatchers;
+
+ private UntypedParamNodeMatcher(
+ java.util.List<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNode>> 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.UntypedParamNode.class, this.submatchers);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNodeMatcher 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.UntypedParamNode>>(this.submatchers);
+ submatchers.add(org.zwobble.precisely.Matchers.has("name", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNode::name, (org.zwobble.precisely.Matcher) name));
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNodeMatcher(submatchers);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNodeMatcher 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.UntypedParamNode>>(this.submatchers);
+ submatchers.add(org.zwobble.precisely.Matchers.has("source", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNode::source, (org.zwobble.precisely.Matcher) source));
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNodeMatcher(submatchers);
+ }
+
+ // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNodeMatcher body
+ // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNodeMatcher body
+}
diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedQueryDefinitionNodeMatcher.java b/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedQueryDefinitionNodeMatcher.java
new file mode 100644
index 0000000..2e0ab23
--- /dev/null
+++ b/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedQueryDefinitionNodeMatcher.java
@@ -0,0 +1,65 @@
+// Generated by hobgoblin.
+
+package org.zwobble.hobgoblin.compiler.ast.untyped;
+
+// Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNodeMatcher imports
+// Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNodeMatcher imports
+
+public final class UntypedQueryDefinitionNodeMatcher implements org.zwobble.precisely.Matcher<java.lang.Object> {
+ public static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNodeMatcher isUntypedQueryDefinitionNode() {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNodeMatcher(java.util.List.of());
+ }
+
+ private final java.util.List<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode>> submatchers;
+
+ private UntypedQueryDefinitionNodeMatcher(
+ java.util.List<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode>> 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.UntypedQueryDefinitionNode.class, this.submatchers);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNodeMatcher 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.UntypedQueryDefinitionNode>>(this.submatchers);
+ submatchers.add(org.zwobble.precisely.Matchers.has("name", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode::name, (org.zwobble.precisely.Matcher) name));
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNodeMatcher(submatchers);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNodeMatcher withDatabaseSchema(org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeLevelExpressionNode> databaseSchema) {
+ var submatchers = new java.util.ArrayList<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode>>(this.submatchers);
+ submatchers.add(org.zwobble.precisely.Matchers.has("databaseSchema", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode::databaseSchema, (org.zwobble.precisely.Matcher) databaseSchema));
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNodeMatcher(submatchers);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNodeMatcher withStatements(org.zwobble.precisely.Matcher<? super java.util.List<org.zwobble.hobgoblin.compiler.ast.untyped.UntypedStatementNode>> statements) {
+ var submatchers = new java.util.ArrayList<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode>>(this.submatchers);
+ submatchers.add(org.zwobble.precisely.Matchers.has("statements", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode::statements, (org.zwobble.precisely.Matcher) statements));
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNodeMatcher(submatchers);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNodeMatcher 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.UntypedQueryDefinitionNode>>(this.submatchers);
+ submatchers.add(org.zwobble.precisely.Matchers.has("docComment", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode::docComment, (org.zwobble.precisely.Matcher) docComment));
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNodeMatcher(submatchers);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNodeMatcher 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.UntypedQueryDefinitionNode>>(this.submatchers);
+ submatchers.add(org.zwobble.precisely.Matchers.has("source", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode::source, (org.zwobble.precisely.Matcher) source));
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNodeMatcher(submatchers);
+ }
+
+ // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNodeMatcher body
+ // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNodeMatcher body
+}
diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedReferenceNodeMatcher.java b/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedReferenceNodeMatcher.java
new file mode 100644
index 0000000..311f24d
--- /dev/null
+++ b/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedReferenceNodeMatcher.java
@@ -0,0 +1,47 @@
+// Generated by hobgoblin.
+
+package org.zwobble.hobgoblin.compiler.ast.untyped;
+
+// Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNodeMatcher imports
+// Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNodeMatcher imports
+
+public final class UntypedReferenceNodeMatcher implements org.zwobble.precisely.Matcher<java.lang.Object> {
+ public static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNodeMatcher isUntypedReferenceNode() {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNodeMatcher(java.util.List.of());
+ }
+
+ private final java.util.List<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNode>> submatchers;
+
+ private UntypedReferenceNodeMatcher(
+ java.util.List<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNode>> 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.UntypedReferenceNode.class, this.submatchers);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNodeMatcher 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.UntypedReferenceNode>>(this.submatchers);
+ submatchers.add(org.zwobble.precisely.Matchers.has("name", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNode::name, (org.zwobble.precisely.Matcher) name));
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNodeMatcher(submatchers);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNodeMatcher 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.UntypedReferenceNode>>(this.submatchers);
+ submatchers.add(org.zwobble.precisely.Matchers.has("source", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNode::source, (org.zwobble.precisely.Matcher) source));
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNodeMatcher(submatchers);
+ }
+
+ // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNodeMatcher body
+ // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNodeMatcher body
+}
diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedReturnNodeMatcher.java b/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedReturnNodeMatcher.java
new file mode 100644
index 0000000..7825b0d
--- /dev/null
+++ b/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedReturnNodeMatcher.java
@@ -0,0 +1,47 @@
+// Generated by hobgoblin.
+
+package org.zwobble.hobgoblin.compiler.ast.untyped;
+
+// Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNodeMatcher imports
+// Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNodeMatcher imports
+
+public final class UntypedReturnNodeMatcher implements org.zwobble.precisely.Matcher<java.lang.Object> {
+ public static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNodeMatcher isUntypedReturnNode() {
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNodeMatcher(java.util.List.of());
+ }
+
+ private final java.util.List<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNode>> submatchers;
+
+ private UntypedReturnNodeMatcher(
+ java.util.List<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNode>> 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.UntypedReturnNode.class, this.submatchers);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNodeMatcher withExpression(org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode> expression) {
+ var submatchers = new java.util.ArrayList<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNode>>(this.submatchers);
+ submatchers.add(org.zwobble.precisely.Matchers.has("expression", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNode::expression, (org.zwobble.precisely.Matcher) expression));
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNodeMatcher(submatchers);
+ }
+
+ public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNodeMatcher 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.UntypedReturnNode>>(this.submatchers);
+ submatchers.add(org.zwobble.precisely.Matchers.has("source", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNode::source, (org.zwobble.precisely.Matcher) source));
+ return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNodeMatcher(submatchers);
+ }
+
+ // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNodeMatcher body
+ // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNodeMatcher body
+}
diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/output/lang/CodeWriterTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/output/CodeWriterTests.java
index 2b3ad6d..9e3f900 100644
--- a/src/test/java/org/zwobble/hobgoblin/compiler/output/lang/CodeWriterTests.java
+++ b/src/test/java/org/zwobble/hobgoblin/compiler/output/CodeWriterTests.java
@@ -1,7 +1,6 @@
-package org.zwobble.hobgoblin.compiler.output.lang;
+package org.zwobble.hobgoblin.compiler.output;
import org.junit.jupiter.api.Test;
-import org.zwobble.hobgoblin.compiler.output.CodeWriter;
import java.io.IOException;
import java.io.StringWriter;
@@ -18,7 +17,7 @@ public class CodeWriterTests {
CodeWriter.writeTo(
file,
- "//",
+ new CodeWriter.CodeWriterConfig("//"),
codeWriter -> {
codeWriter.writeHeader();
codeWriter.write("Before");
@@ -51,7 +50,7 @@ public class CodeWriterTests {
CodeWriter.writeTo(
file,
- "//",
+ new CodeWriter.CodeWriterConfig("//"),
codeWriter -> {
codeWriter.writeHeader();
codeWriter.write("Before");
@@ -89,7 +88,7 @@ public class CodeWriterTests {
CodeWriter.writeTo(
file,
- "//",
+ new CodeWriter.CodeWriterConfig("//"),
codeWriter -> {
codeWriter.writeHeader();
codeWriter.writeCustomArea("head");
@@ -124,7 +123,7 @@ public class CodeWriterTests {
CodeWriter.writeTo(
file,
- "//",
+ new CodeWriter.CodeWriterConfig("//"),
codeWriter -> {
codeWriter.writeHeader();
codeWriter.writeCustomArea("head");
@@ -135,4 +134,81 @@ public class CodeWriterTests {
assertThat(stringWriter.toString(), equalTo(""));
assertThat(file.isWriterOpened(), equalTo(false));
}
+
+ @Test
+ public void strippingDoesNothingToFileWithoutHeader() {
+ var originalContents = """
+ Hello, world!
+ """;
+
+ var result = CodeWriter.stripFileContents(
+ originalContents,
+ new CodeWriter.CodeWriterConfig("//")
+ );
+
+ assertThat(result, equalTo(new CodeWriter.StripResult.Unchanged()));
+ }
+
+ @Test
+ public void whenFileHasNoCustomAreasThenFileIsDeleted() {
+ var originalContents = """
+ // Generated by hobgoblin.
+
+ Hello, world!
+ """;
+
+ var result = CodeWriter.stripFileContents(
+ originalContents,
+ new CodeWriter.CodeWriterConfig("//")
+ );
+
+ assertThat(result, equalTo(new CodeWriter.StripResult.Delete()));
+ }
+
+ @Test
+ public void whenCustomAreasAreAllEmptyThenFileIsDeleted() {
+ var originalContents = """
+ // Generated by hobgoblin.
+
+ Before
+ // Custom area start: body
+ // Custom area end: body
+ After
+ """;
+
+ var result = CodeWriter.stripFileContents(
+ originalContents,
+ new CodeWriter.CodeWriterConfig("//")
+ );
+
+ assertThat(result, equalTo(new CodeWriter.StripResult.Delete()));
+ }
+
+ @Test
+ public void nonEmptyCustomAreasArePreserved() {
+ var originalContents = """
+ // Generated by hobgoblin.
+
+ Before
+ // Custom area start: head
+ Custom head.
+ // Custom area end: head
+ // Custom area start: body
+ // Custom area end: body
+ After
+ """;
+
+ var result = CodeWriter.stripFileContents(
+ originalContents,
+ new CodeWriter.CodeWriterConfig("//")
+ );
+
+ assertThat(result, equalTo(new CodeWriter.StripResult.NewContent("""
+ // Generated by hobgoblin.
+
+ // Custom area start: head
+ Custom head.
+ // Custom area end: head
+ """)));
+ }
}
diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserCallTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserCallTests.java
new file mode 100644
index 0000000..64e84de
--- /dev/null
+++ b/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserCallTests.java
@@ -0,0 +1,61 @@
+package org.zwobble.hobgoblin.compiler.parser;
+
+import org.junit.jupiter.api.Test;
+
+import static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedCallNodeMatcher.isUntypedCallNode;
+import static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNodeMatcher.isUntypedReferenceNode;
+import static org.zwobble.hobgoblin.compiler.parser.ParserTesting.parseString;
+import static org.zwobble.precisely.AssertThat.assertThat;
+import static org.zwobble.precisely.Matchers.equalTo;
+import static org.zwobble.precisely.Matchers.isSequence;
+
+public class ParserCallTests {
+ @Test
+ public void canParseCallWithNoArguments() {
+ var source = "f()";
+
+ var node = parseString(source, Parser::parseTopLevelExpression);
+
+ assertThat(node, isUntypedCallNode()
+ .withReceiver(isUntypedReferenceNode()
+ .withName(equalTo("f"))
+ )
+ .withArgs(isSequence())
+ );
+ }
+
+ @Test
+ public void canParseCallWithOnePositionalArgument() {
+ var source = "f(a)";
+
+ var node = parseString(source, Parser::parseTopLevelExpression);
+
+ assertThat(node, isUntypedCallNode()
+ .withReceiver(isUntypedReferenceNode()
+ .withName(equalTo("f"))
+ )
+ .withArgs(isSequence(
+ isUntypedReferenceNode().withName(equalTo("a"))
+ ))
+ );
+ }
+
+ @Test
+ public void canParseCallWithMultiplePositionalArguments() {
+ var source = "f(a, b, c)";
+
+ var node = parseString(source, Parser::parseTopLevelExpression);
+
+ assertThat(node, isUntypedCallNode()
+ .withReceiver(isUntypedReferenceNode()
+ .withName(equalTo("f"))
+ )
+ .withArgs(isSequence(
+ isUntypedReferenceNode().withName(equalTo("a")),
+ isUntypedReferenceNode().withName(equalTo("b")),
+ isUntypedReferenceNode().withName(equalTo("c"))
+ ))
+ );
+ }
+}
+
diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserFunctionExpressionTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserFunctionExpressionTests.java
new file mode 100644
index 0000000..99cf3c0
--- /dev/null
+++ b/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserFunctionExpressionTests.java
@@ -0,0 +1,55 @@
+package org.zwobble.hobgoblin.compiler.parser;
+
+import org.junit.jupiter.api.Test;
+
+import static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedFunctionExpressionNodeMatcher.isUntypedFunctionExpressionNode;
+import static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedParamNodeMatcher.isUntypedParamNode;
+import static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNodeMatcher.isUntypedReferenceNode;
+import static org.zwobble.hobgoblin.compiler.parser.ParserTesting.parseString;
+import static org.zwobble.precisely.AssertThat.assertThat;
+import static org.zwobble.precisely.Matchers.equalTo;
+import static org.zwobble.precisely.Matchers.isSequence;
+
+public class ParserFunctionExpressionTests {
+ @Test
+ public void canParseFunctionExpressionWithNoParams() {
+ var source = "$() => x";
+
+ var node = parseString(source, Parser::parseTopLevelExpression);
+
+ assertThat(node, isUntypedFunctionExpressionNode()
+ .withParams(isSequence())
+ .withBody(isUntypedReferenceNode().withName(equalTo("x")))
+ );
+ }
+
+ @Test
+ public void canParseFunctionExpressionWithOneParam() {
+ var source = "$(a) => x";
+
+ var node = parseString(source, Parser::parseTopLevelExpression);
+
+ assertThat(node, isUntypedFunctionExpressionNode()
+ .withParams(isSequence(
+ isUntypedParamNode().withName(equalTo("a"))
+ ))
+ .withBody(isUntypedReferenceNode().withName(equalTo("x")))
+ );
+ }
+ @Test
+ public void canParseFunctionExpressionWithMultipleParams() {
+ var source = "$(a, b, c) => x";
+
+ var node = parseString(source, Parser::parseTopLevelExpression);
+
+ assertThat(node, isUntypedFunctionExpressionNode()
+ .withParams(isSequence(
+ isUntypedParamNode().withName(equalTo("a")),
+ isUntypedParamNode().withName(equalTo("b")),
+ isUntypedParamNode().withName(equalTo("c"))
+ ))
+ .withBody(isUntypedReferenceNode().withName(equalTo("x")))
+ );
+ }
+}
+
diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserMemberAccessTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserMemberAccessTests.java
new file mode 100644
index 0000000..d28cc2b
--- /dev/null
+++ b/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserMemberAccessTests.java
@@ -0,0 +1,26 @@
+package org.zwobble.hobgoblin.compiler.parser;
+
+import org.junit.jupiter.api.Test;
+
+import static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNodeMatcher.isUntypedMemberAccessNode;
+import static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNodeMatcher.isUntypedReferenceNode;
+import static org.zwobble.hobgoblin.compiler.parser.ParserTesting.parseString;
+import static org.zwobble.precisely.AssertThat.assertThat;
+import static org.zwobble.precisely.Matchers.equalTo;
+
+public class ParserMemberAccessTests {
+ @Test
+ public void canParseMemberAccess() {
+ var source = "author.name";
+
+ var node = parseString(source, Parser::parseTopLevelExpression);
+
+ assertThat(node, isUntypedMemberAccessNode()
+ .withReceiver(isUntypedReferenceNode()
+ .withName(equalTo("author"))
+ )
+ .withFieldName(equalTo("name"))
+ );
+ }
+}
+
diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserQueryDefinitionTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserQueryDefinitionTests.java
new file mode 100644
index 0000000..e7676c9
--- /dev/null
+++ b/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserQueryDefinitionTests.java
@@ -0,0 +1,78 @@
+package org.zwobble.hobgoblin.compiler.parser;
+
+import org.junit.jupiter.api.Test;
+
+import static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNodeMatcher.isUntypedQueryDefinitionNode;
+import static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNodeMatcher.isUntypedReferenceNode;
+import static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNodeMatcher.isUntypedReturnNode;
+import static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeLevelReferenceNodeMatcher.isUntypedTypeLevelReferenceNode;
+import static org.zwobble.hobgoblin.compiler.parser.ParserTesting.parseString;
+import static org.zwobble.precisely.AssertThat.assertThat;
+import static org.zwobble.precisely.Matchers.equalTo;
+import static org.zwobble.precisely.Matchers.isSequence;
+
+public class ParserQueryDefinitionTests {
+ @Test
+ public void canParseQueryDefinitionWithNoStatements() {
+ var source = """
+ query allAuthors() on BlogAppDatabase {
+ }""";
+
+ var node = parseString(source, Parser::parseNamespaceStatement);
+
+ assertThat(node, isUntypedQueryDefinitionNode()
+ .withName(equalTo("allAuthors"))
+ .withDatabaseSchema(isUntypedTypeLevelReferenceNode().withName(equalTo("BlogAppDatabase")))
+ .withStatements(isSequence())
+ );
+ }
+
+ @Test
+ public void canParseQueryDefinitionWithSingleStatement() {
+ var source = """
+ query allAuthors() on BlogAppDatabase {
+ return x;
+ }""";
+
+ var node = parseString(source, Parser::parseNamespaceStatement);
+
+ assertThat(node, isUntypedQueryDefinitionNode()
+ .withName(equalTo("allAuthors"))
+ .withDatabaseSchema(isUntypedTypeLevelReferenceNode().withName(equalTo("BlogAppDatabase")))
+ .withStatements(isSequence(
+ isUntypedReturnNode()
+ .withExpression(isUntypedReferenceNode()
+ .withName(equalTo("x"))
+ )
+ ))
+ );
+
+ }
+
+ @Test
+ public void canParseQueryDefinitionWithMultipleStatements() {
+ var source = """
+ query allAuthors() on BlogAppDatabase {
+ return x;
+ return y;
+ }""";
+
+ var node = parseString(source, Parser::parseNamespaceStatement);
+
+ assertThat(node, isUntypedQueryDefinitionNode()
+ .withName(equalTo("allAuthors"))
+ .withDatabaseSchema(isUntypedTypeLevelReferenceNode().withName(equalTo("BlogAppDatabase")))
+ .withStatements(isSequence(
+ isUntypedReturnNode()
+ .withExpression(isUntypedReferenceNode()
+ .withName(equalTo("x"))
+ ),
+ isUntypedReturnNode()
+ .withExpression(isUntypedReferenceNode()
+ .withName(equalTo("y"))
+ )
+ ))
+ );
+ }
+}
+
diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserReferenceTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserReferenceTests.java
new file mode 100644
index 0000000..fdd3add
--- /dev/null
+++ b/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserReferenceTests.java
@@ -0,0 +1,22 @@
+package org.zwobble.hobgoblin.compiler.parser;
+
+import org.junit.jupiter.api.Test;
+
+import static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNodeMatcher.isUntypedReferenceNode;
+import static org.zwobble.hobgoblin.compiler.parser.ParserTesting.parseString;
+import static org.zwobble.precisely.AssertThat.assertThat;
+import static org.zwobble.precisely.Matchers.equalTo;
+
+public class ParserReferenceTests {
+ @Test
+ public void canParseReference() {
+ var source = "authors";
+
+ var node = parseString(source, Parser::parseTopLevelExpression);
+
+ assertThat(node, isUntypedReferenceNode()
+ .withName(equalTo("authors"))
+ );
+ }
+}
+
diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserReturnTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserReturnTests.java
new file mode 100644
index 0000000..64ce562
--- /dev/null
+++ b/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserReturnTests.java
@@ -0,0 +1,25 @@
+package org.zwobble.hobgoblin.compiler.parser;
+
+import org.junit.jupiter.api.Test;
+
+import static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNodeMatcher.isUntypedReferenceNode;
+import static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNodeMatcher.isUntypedReturnNode;
+import static org.zwobble.hobgoblin.compiler.parser.ParserTesting.parseString;
+import static org.zwobble.precisely.AssertThat.assertThat;
+import static org.zwobble.precisely.Matchers.equalTo;
+
+public class ParserReturnTests {
+ @Test
+ public void canParseReturn() {
+ var source = "return x;";
+
+ var node = parseString(source, Parser::parseStatement);
+
+ assertThat(node, isUntypedReturnNode()
+ .withExpression(isUntypedReferenceNode()
+ .withName(equalTo("x"))
+ )
+ );
+ }
+}
+
diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/parser/TokenizerTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/parser/TokenizerTests.java
index 39aded5..d5b7347 100644
--- a/src/test/java/org/zwobble/hobgoblin/compiler/parser/TokenizerTests.java
+++ b/src/test/java/org/zwobble/hobgoblin/compiler/parser/TokenizerTests.java
@@ -173,6 +173,17 @@ public class TokenizerTests {
}
@Test
+ public void symbolDollarIsTokenized() {
+ var sourceText = SourceText.fromString("<string>", "$");
+
+ var tokens = Tokenizer.tokenize(sourceText);
+
+ assertThat(tokens.tokens(), isSequence(
+ equalTo(new Token(TokenType.SYMBOL_DOLLAR, sourceRange(sourceText, 0, 1)))
+ ));
+ }
+
+ @Test
public void symbolDotIsTokenized() {
var sourceText = SourceText.fromString("<string>", ".");
@@ -195,6 +206,17 @@ public class TokenizerTests {
}
@Test
+ public void symbolFatArrowIsTokenized() {
+ var sourceText = SourceText.fromString("<string>", "=>");
+
+ var tokens = Tokenizer.tokenize(sourceText);
+
+ assertThat(tokens.tokens(), isSequence(
+ equalTo(new Token(TokenType.SYMBOL_FAT_ARROW, sourceRange(sourceText, 0, 2)))
+ ));
+ }
+
+ @Test
public void symbolForwardSlashIsTokenized() {
var sourceText = SourceText.fromString("<string>", "/");
diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerDatabaseSchemaDefinitionTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerDatabaseSchemaDefinitionTests.java
index 08fdd47..daecb54 100644
--- a/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerDatabaseSchemaDefinitionTests.java
+++ b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerDatabaseSchemaDefinitionTests.java
@@ -6,20 +6,17 @@ import org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode;
import org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeLevelReferenceNode;
import org.zwobble.hobgoblin.compiler.builtins.NativeTypes;
import org.zwobble.hobgoblin.compiler.sources.NullSource;
-import org.zwobble.hobgoblin.compiler.types.Field;
-import org.zwobble.hobgoblin.compiler.types.NamespaceName;
-import org.zwobble.hobgoblin.compiler.types.SimpleStructType;
-import org.zwobble.hobgoblin.compiler.types.Types;
+import org.zwobble.hobgoblin.compiler.types.*;
import java.util.List;
+import java.util.Map;
import java.util.Optional;
import static org.zwobble.hobgoblin.compiler.ast.typed.TypedDatabaseSchemaDefinitionNodeMatcher.isTypedDatabaseSchemaDefinitionNode;
import static org.zwobble.hobgoblin.compiler.ast.typed.TypedTableDefinitionNodeMatcher.isTypedTableDefinitionNode;
import static org.zwobble.hobgoblin.compiler.typechecker.TypeCheckerTesting.typeCheckNamespaceStatement;
import static org.zwobble.precisely.AssertThat.assertThat;
-import static org.zwobble.precisely.Matchers.equalTo;
-import static org.zwobble.precisely.Matchers.isSequence;
+import static org.zwobble.precisely.Matchers.*;
public class TypeCheckerDatabaseSchemaDefinitionTests {
@Test
@@ -54,5 +51,20 @@ public class TypeCheckerDatabaseSchemaDefinitionTests {
.withRowType(equalTo(authorType))
))
);
+ assertThat(
+ namespaceContext.lookupType("blogApp"),
+ isOptionalOf(equalTo(Types.databaseSchema(new DatabaseSchema(NamespaceName.of("App"), "blogApp"))))
+ );
+ var typesInfo = namespaceContext.toTypesInfo();
+ var schemaInfo = typesInfo.databaseSchemaInfo(new DatabaseSchema(NamespaceName.of("App"), "blogApp"));
+ assertThat(schemaInfo.tables().entrySet(), isSequence(
+ allOf(
+ has("key", Map.Entry::getKey, equalTo("authors")),
+ has("value", Map.Entry::getValue, allOf(
+ has("rowType", TableInfo::rowType, equalTo(authorType)),
+ has("primaryKey", TableInfo::primaryKey, equalTo(new Field("id", NativeTypes.INT_32, NullSource.INSTANCE)))
+ ))
+ )
+ ));
}
}
diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerQueryDefinitionTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerQueryDefinitionTests.java
new file mode 100644
index 0000000..4ecc1c6
--- /dev/null
+++ b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerQueryDefinitionTests.java
@@ -0,0 +1,40 @@
+package org.zwobble.hobgoblin.compiler.typechecker;
+
+import org.junit.jupiter.api.Test;
+import org.zwobble.hobgoblin.compiler.ast.untyped.UntypedQueryDefinitionNode;
+import org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReferenceNode;
+import org.zwobble.hobgoblin.compiler.ast.untyped.UntypedReturnNode;
+import org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeLevelReferenceNode;
+import org.zwobble.hobgoblin.compiler.sources.NullSource;
+import org.zwobble.hobgoblin.compiler.types.*;
+
+import static org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNodeMatcher.isTypedQueryDefinitionNode;
+import static org.zwobble.hobgoblin.compiler.typechecker.TypeCheckerTesting.typeCheckNamespaceStatement;
+import static org.zwobble.precisely.AssertThat.assertThat;
+import static org.zwobble.precisely.Matchers.equalTo;
+
+public class TypeCheckerQueryDefinitionTests {
+ @Test
+ public void queryForAllTableRows() {
+ var untyped = UntypedQueryDefinitionNode.arbitrary()
+ .withName("allAuthors")
+ .withDatabaseSchema(UntypedTypeLevelReferenceNode.arbitrary().withName("blogApp"))
+ .addStatement(UntypedReturnNode.arbitrary().withExpression(
+ UntypedReferenceNode.arbitrary().withName("authors")
+ ))
+ .build();
+ var globalContext = TypeCheckerContextArb.globalContext();
+ var namespaceName = NamespaceName.of("App");
+ var namespaceContext = globalContext.enterNamespace(namespaceName);
+ var databaseSchema = new DatabaseSchema(namespaceName, "blogApp");
+ var table = new Table(databaseSchema, "authors");
+ namespaceContext.declare("authors", Types.table(table), NullSource.INSTANCE);
+
+ var typed = typeCheckNamespaceStatement(untyped, namespaceContext);
+
+ assertThat(typed, isTypedQueryDefinitionNode()
+ .withName(equalTo("allAuthors"))
+ .withTable(equalTo(table))
+ );
+ }
+}
diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerTableDefinitionTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerTableDefinitionTests.java
index a32945a..989fa39 100644
--- a/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerTableDefinitionTests.java
+++ b/src/test/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerTableDefinitionTests.java
@@ -9,6 +9,7 @@ import org.zwobble.hobgoblin.compiler.typechecker.errors.NoSuchFieldError;
import org.zwobble.hobgoblin.compiler.typechecker.errors.TableRowTypeMustBeStructError;
import org.zwobble.hobgoblin.compiler.types.*;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Optional;
@@ -37,11 +38,16 @@ public class TypeCheckerTableDefinitionTests {
new Field("id", NativeTypes.INT_32, NullSource.INSTANCE)
)));
- var typed = typeCheckDatabaseSchemaStatement(untyped, namespaceContext);
+ var typed = typeCheckDatabaseSchemaStatement(
+ untyped,
+ new DatabaseSchemaInfo(new LinkedHashMap<>()),
+ namespaceContext
+ );
assertThat(typed, isTypedTableDefinitionNode()
.withName(equalTo("authors"))
.withRowType(equalTo(authorType))
+ .withPrimaryKey(equalTo(new Field("id", NativeTypes.INT_32, NullSource.INSTANCE)))
);
}
@@ -61,7 +67,11 @@ public class TypeCheckerTableDefinitionTests {
var error = assertThrows(
TableRowTypeMustBeStructError.class,
- () -> typeCheckDatabaseSchemaStatement(untyped, namespaceContext)
+ () -> typeCheckDatabaseSchemaStatement(
+ untyped,
+ new DatabaseSchemaInfo(new LinkedHashMap<>()),
+ namespaceContext
+ )
);
assertThat(error.rowType(), equalTo(authorType));
@@ -87,7 +97,11 @@ public class TypeCheckerTableDefinitionTests {
var error = assertThrows(
NoSuchFieldError.class,
- () -> typeCheckDatabaseSchemaStatement(untyped, namespaceContext)
+ () -> typeCheckDatabaseSchemaStatement(
+ untyped,
+ new DatabaseSchemaInfo(new LinkedHashMap<>()),
+ namespaceContext
+ )
);
assertThat(error.type(), equalTo(authorType));
diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/util/SequencedMaps.java b/src/test/java/org/zwobble/hobgoblin/compiler/util/SequencedMaps.java
new file mode 100644
index 0000000..b19d3d1
--- /dev/null
+++ b/src/test/java/org/zwobble/hobgoblin/compiler/util/SequencedMaps.java
@@ -0,0 +1,23 @@
+package org.zwobble.hobgoblin.compiler.util;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.SequencedMap;
+
+public class SequencedMaps {
+ private SequencedMaps() {
+ }
+
+ @SafeVarargs
+ public static <K, V> SequencedMap<K, V> ofEntries(
+ Map.Entry<K, V>... entries
+ ) {
+ var map = new LinkedHashMap<K, V>(entries.length);
+
+ for (var entry : entries) {
+ map.put(entry.getKey(), entry.getValue());
+ }
+
+ return map;
+ }
+}