diff options
Diffstat (limited to 'src/main/java/org/zwobble')
66 files changed, 1985 insertions, 80 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/Relation.java b/src/main/java/org/zwobble/hobgoblin/compiler/ast/typed/Relation.java new file mode 100644 index 0000000..7f08714 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/ast/typed/Relation.java @@ -0,0 +1,18 @@ +// Generated by hobgoblin. + +package org.zwobble.hobgoblin.compiler.ast.typed; + +// Custom area start: org.zwobble.hobgoblin.compiler.ast.typed.Relation imports +// Custom area end: org.zwobble.hobgoblin.compiler.ast.typed.Relation imports + +public sealed interface Relation permits org.zwobble.hobgoblin.compiler.ast.typed.RelationTable { + public interface Builder { + public org.zwobble.hobgoblin.compiler.ast.typed.Relation build(); + + // Custom area start: org.zwobble.hobgoblin.compiler.ast.typed.Relation.Builder body + // Custom area end: org.zwobble.hobgoblin.compiler.ast.typed.Relation.Builder body + } + + // Custom area start: org.zwobble.hobgoblin.compiler.ast.typed.Relation body + // Custom area end: org.zwobble.hobgoblin.compiler.ast.typed.Relation body +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/ast/typed/RelationTable.java b/src/main/java/org/zwobble/hobgoblin/compiler/ast/typed/RelationTable.java new file mode 100644 index 0000000..d62753e --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/ast/typed/RelationTable.java @@ -0,0 +1,32 @@ +// Generated by hobgoblin. + +package org.zwobble.hobgoblin.compiler.ast.typed; + +// Custom area start: org.zwobble.hobgoblin.compiler.ast.typed.RelationTable imports +// Custom area end: org.zwobble.hobgoblin.compiler.ast.typed.RelationTable imports + +public record RelationTable( + org.zwobble.hobgoblin.compiler.types.Table table +) implements org.zwobble.hobgoblin.compiler.ast.typed.Relation { + public static org.zwobble.hobgoblin.compiler.ast.typed.RelationTable.Builder arbitrary() { + return new org.zwobble.hobgoblin.compiler.ast.typed.RelationTable.Builder(org.zwobble.hobgoblin.compiler.types.HobgoblinNativeTypes.arbitraryTable()); + } + + public record Builder( + org.zwobble.hobgoblin.compiler.types.Table table + ) implements org.zwobble.hobgoblin.compiler.ast.typed.Relation.Builder { + public org.zwobble.hobgoblin.compiler.ast.typed.RelationTable build() { + return new org.zwobble.hobgoblin.compiler.ast.typed.RelationTable(table); + } + + public org.zwobble.hobgoblin.compiler.ast.typed.RelationTable.Builder withTable(org.zwobble.hobgoblin.compiler.types.Table table) { + return new org.zwobble.hobgoblin.compiler.ast.typed.RelationTable.Builder(table); + } + + // Custom area start: org.zwobble.hobgoblin.compiler.ast.typed.RelationTable.Builder body + // Custom area end: org.zwobble.hobgoblin.compiler.ast.typed.RelationTable.Builder body + } + + // Custom area start: org.zwobble.hobgoblin.compiler.ast.typed.RelationTable body + // Custom area end: org.zwobble.hobgoblin.compiler.ast.typed.RelationTable body +} 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..dc61d28 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/ast/typed/TypedQueryDefinitionNode.java @@ -0,0 +1,54 @@ +// 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.ast.typed.Relation relation, + 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.ast.typed.RelationTable.arbitrary().build(), org.zwobble.hobgoblin.compiler.ast.HobgoblinNativeAst.arbitraryDocComment(), org.zwobble.hobgoblin.compiler.sources.HobgoblinNativeSources.arbitrarySource()); + } + + public record Builder( + String name, + org.zwobble.hobgoblin.compiler.ast.typed.Relation relation, + 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, relation, 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, relation, docComment, source); + } + + public org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode.Builder withRelation(org.zwobble.hobgoblin.compiler.ast.typed.Relation relation) { + return new org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode.Builder(name, relation, docComment, source); + } + + public org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode.Builder withRelation(org.zwobble.hobgoblin.compiler.ast.typed.Relation.Builder relation) { + return new org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode.Builder(name, relation.build(), 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, relation, 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, relation, 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/UntypedBinaryOperationNode.java b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedBinaryOperationNode.java new file mode 100644 index 0000000..b6fb024 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedBinaryOperationNode.java @@ -0,0 +1,58 @@ +// Generated by hobgoblin. + +package org.zwobble.hobgoblin.compiler.ast.untyped; + +// Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedBinaryOperationNode imports +// Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedBinaryOperationNode imports + +public record UntypedBinaryOperationNode( + org.zwobble.hobgoblin.compiler.ast.untyped.UntypedBinaryOperator operator, + org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode left, + org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode right, + org.zwobble.hobgoblin.compiler.sources.Source source +) implements org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode { + public static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedBinaryOperationNode.Builder arbitrary() { + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedBinaryOperationNode.Builder(org.zwobble.hobgoblin.compiler.ast.untyped.UntypedBinaryOperator.EQUALS, org.zwobble.hobgoblin.compiler.ast.untyped.UntypedNumberLiteralNode.arbitrary().build(), org.zwobble.hobgoblin.compiler.ast.untyped.UntypedNumberLiteralNode.arbitrary().build(), org.zwobble.hobgoblin.compiler.sources.HobgoblinNativeSources.arbitrarySource()); + } + + public record Builder( + org.zwobble.hobgoblin.compiler.ast.untyped.UntypedBinaryOperator operator, + org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode left, + org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode right, + org.zwobble.hobgoblin.compiler.sources.Source source + ) implements org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode.Builder { + public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedBinaryOperationNode build() { + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedBinaryOperationNode(operator, left, right, source); + } + + public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedBinaryOperationNode.Builder withOperator(org.zwobble.hobgoblin.compiler.ast.untyped.UntypedBinaryOperator operator) { + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedBinaryOperationNode.Builder(operator, left, right, source); + } + + public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedBinaryOperationNode.Builder withLeft(org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode left) { + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedBinaryOperationNode.Builder(operator, left, right, source); + } + + public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedBinaryOperationNode.Builder withLeft(org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode.Builder left) { + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedBinaryOperationNode.Builder(operator, left.build(), right, source); + } + + public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedBinaryOperationNode.Builder withRight(org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode right) { + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedBinaryOperationNode.Builder(operator, left, right, source); + } + + public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedBinaryOperationNode.Builder withRight(org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode.Builder right) { + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedBinaryOperationNode.Builder(operator, left, right.build(), source); + } + + public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedBinaryOperationNode.Builder withSource(org.zwobble.hobgoblin.compiler.sources.Source source) { + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedBinaryOperationNode.Builder(operator, left, right, source); + } + + // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedBinaryOperationNode.Builder body + // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedBinaryOperationNode.Builder body + } + + // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedBinaryOperationNode body + // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedBinaryOperationNode body +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedBinaryOperator.java b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedBinaryOperator.java new file mode 100644 index 0000000..b479e9b --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedBinaryOperator.java @@ -0,0 +1,13 @@ +// Generated by hobgoblin. + +package org.zwobble.hobgoblin.compiler.ast.untyped; + +// Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedBinaryOperator imports +// Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedBinaryOperator imports + +public enum UntypedBinaryOperator { + EQUALS + + // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedBinaryOperator body + // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedBinaryOperator 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..8da37c1 --- /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.UntypedNumberLiteralNode.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..2fd499e --- /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.UntypedBinaryOperationNode, 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.UntypedNumberLiteralNode, 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..d4a6034 --- /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.UntypedNumberLiteralNode.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..4fef83e --- /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 memberName, + 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.UntypedNumberLiteralNode.arbitrary().build(), "", org.zwobble.hobgoblin.compiler.sources.HobgoblinNativeSources.arbitrarySource()); + } + + public record Builder( + org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode receiver, + String memberName, + 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, memberName, 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, memberName, 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(), memberName, source); + } + + public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNode.Builder withMemberName(String memberName) { + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedMemberAccessNode.Builder(receiver, memberName, 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, memberName, 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/UntypedNumberLiteralNode.java b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedNumberLiteralNode.java new file mode 100644 index 0000000..1e041ea --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedNumberLiteralNode.java @@ -0,0 +1,38 @@ +// Generated by hobgoblin. + +package org.zwobble.hobgoblin.compiler.ast.untyped; + +// Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedNumberLiteralNode imports +// Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedNumberLiteralNode imports + +public record UntypedNumberLiteralNode( + java.math.BigDecimal value, + org.zwobble.hobgoblin.compiler.sources.Source source +) implements org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode { + public static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedNumberLiteralNode.Builder arbitrary() { + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedNumberLiteralNode.Builder(org.zwobble.hobgoblin.compiler.math.HobgoblinNativeMath.arbitraryBigDecimal(), org.zwobble.hobgoblin.compiler.sources.HobgoblinNativeSources.arbitrarySource()); + } + + public record Builder( + java.math.BigDecimal value, + org.zwobble.hobgoblin.compiler.sources.Source source + ) implements org.zwobble.hobgoblin.compiler.ast.untyped.UntypedExpressionNode.Builder { + public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedNumberLiteralNode build() { + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedNumberLiteralNode(value, source); + } + + public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedNumberLiteralNode.Builder withValue(java.math.BigDecimal value) { + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedNumberLiteralNode.Builder(value, source); + } + + public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedNumberLiteralNode.Builder withSource(org.zwobble.hobgoblin.compiler.sources.Source source) { + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedNumberLiteralNode.Builder(value, source); + } + + // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedNumberLiteralNode.Builder body + // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedNumberLiteralNode.Builder body + } + + // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedNumberLiteralNode body + // Custom area end: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedNumberLiteralNode body +} 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..b48a95c --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedQueryDefinitionNode.java @@ -0,0 +1,62 @@ +// 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, + 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("", java.util.List.of(), org.zwobble.hobgoblin.compiler.ast.HobgoblinNativeAst.arbitraryDocComment(), org.zwobble.hobgoblin.compiler.sources.HobgoblinNativeSources.arbitrarySource()); + } + + public record Builder( + String name, + 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, 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, 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, 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, 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, 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, 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, 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..03c3446 --- /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.UntypedNumberLiteralNode.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/ast/untyped/UntypedTableDefinitionNode.java b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedTableDefinitionNode.java index ebff463..072d12a 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedTableDefinitionNode.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedTableDefinitionNode.java @@ -8,18 +8,18 @@ package org.zwobble.hobgoblin.compiler.ast.untyped; public record UntypedTableDefinitionNode( String name, org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeLevelExpressionNode rowType, - String primaryKey, + org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeLevelReferenceNode primaryKey, org.zwobble.hobgoblin.compiler.ast.DocComment docComment, org.zwobble.hobgoblin.compiler.sources.Source source ) implements org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaStatementNode { public static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder arbitrary() { - return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder("", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeLevelReferenceNode.arbitrary().build(), "", org.zwobble.hobgoblin.compiler.ast.HobgoblinNativeAst.arbitraryDocComment(), org.zwobble.hobgoblin.compiler.sources.HobgoblinNativeSources.arbitrarySource()); + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder("", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeLevelReferenceNode.arbitrary().build(), org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeLevelReferenceNode.arbitrary().build(), 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 rowType, - String primaryKey, + org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeLevelReferenceNode primaryKey, org.zwobble.hobgoblin.compiler.ast.DocComment docComment, org.zwobble.hobgoblin.compiler.sources.Source source ) implements org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaStatementNode.Builder { @@ -39,10 +39,14 @@ public record UntypedTableDefinitionNode( return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder(name, rowType.build(), primaryKey, docComment, source); } - public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder withPrimaryKey(String primaryKey) { + public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder withPrimaryKey(org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeLevelReferenceNode primaryKey) { return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder(name, rowType, primaryKey, docComment, source); } + public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder withPrimaryKey(org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeLevelReferenceNode.Builder primaryKey) { + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder(name, rowType, primaryKey.build(), docComment, source); + } + public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder withDocComment(org.zwobble.hobgoblin.compiler.ast.DocComment docComment) { return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder(name, rowType, primaryKey, docComment, source); } diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/math/HobgoblinNativeMath.java b/src/main/java/org/zwobble/hobgoblin/compiler/math/HobgoblinNativeMath.java new file mode 100644 index 0000000..1592b50 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/math/HobgoblinNativeMath.java @@ -0,0 +1,11 @@ +package org.zwobble.hobgoblin.compiler.math; + +import java.math.BigDecimal; + +public class HobgoblinNativeMath { + private HobgoblinNativeMath() {} + + public static BigDecimal arbitraryBigDecimal() { + return BigDecimal.ZERO; + } +} 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/sql/SqlGenerator.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/sql/SqlGenerator.java index be847d5..4a23fa1 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/sql/SqlGenerator.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/sql/SqlGenerator.java @@ -1,7 +1,11 @@ package org.zwobble.hobgoblin.compiler.output.generators.sql; +import org.zwobble.hobgoblin.compiler.ast.typed.Relation; +import org.zwobble.hobgoblin.compiler.ast.typed.RelationTable; +import org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode; import org.zwobble.hobgoblin.compiler.ast.typed.TypedTableDefinitionNode; import org.zwobble.hobgoblin.compiler.builtins.NativeTypes; +import org.zwobble.hobgoblin.compiler.errors.InternalError; import org.zwobble.hobgoblin.compiler.output.lang.sql.ast.*; import org.zwobble.hobgoblin.compiler.typechecker.TypesInfo; import org.zwobble.hobgoblin.compiler.types.SimpleStructType; @@ -50,6 +54,55 @@ public class SqlGenerator { } } + public SqlStatement generateQueryDefinition( + TypedQueryDefinitionNode queryDefinition, + TypesInfo typesInfo + ) { + return generateRelation(queryDefinition.relation(), typesInfo); + } + + SqlSelectStatement generateRelation(Relation relation, TypesInfo typesInfo) { + switch (relation) { + case RelationTable relationTable -> { + var table = relationTable.table(); + var schemaInfo = typesInfo.databaseSchemaInfo(table.databaseSchema()); + var tableInfo = schemaInfo.tables().get(table.name()); + + var fields = typesInfo.fieldsOf(tableInfo.rowType()) + .orElse(List.of()); + + // The type-checker should have verified that the row type has + // fields, so don't try to handle gracefully here. + if (fields.isEmpty()) { + throw new InternalError("row type has no fields"); + } + + var columns = fields.stream() + .map(field -> { + var columnName = generateColumnName(field.name()); + return new SqlResultColumn( + new SqlRef(columnName), + columnName + ); + }) + .toList(); + + // Order by the primary key to ensure stable ordering. + var orderBy = List.of( + new SqlOrderingTerm(new SqlRef( + generateColumnName(tableInfo.primaryKey().name()) + )) + ); + + return new SqlSelectStatement( + columns, + generateTableName(table.name()), + orderBy + ); + } + } + } + private SqlIdentifier generateColumnName(String fieldName) { return new SqlIdentifier(Casing.lowerCamelCaseToSnakeCase(fieldName)); } 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..f34a629 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 @@ -1,12 +1,10 @@ package org.zwobble.hobgoblin.compiler.output.generators.sqlscripts; -import org.zwobble.hobgoblin.compiler.ast.typed.TypedDatabaseSchemaDefinitionNode; -import org.zwobble.hobgoblin.compiler.ast.typed.TypedDatabaseSchemaStatementNode; -import org.zwobble.hobgoblin.compiler.ast.typed.TypedNamespaceNode; -import org.zwobble.hobgoblin.compiler.ast.typed.TypedTableDefinitionNode; +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.sql.SqlGenerator; import org.zwobble.hobgoblin.compiler.output.lang.sql.SqlWriter; import org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlScript; @@ -69,17 +67,55 @@ public class SqlScriptsGenerator implements Generator { ) throws IOException { for (var namespace : namespaces) { for (var namespaceStatement : namespace.body()) { - if (namespaceStatement instanceof TypedDatabaseSchemaDefinitionNode databaseSchemaDefinition) { - generateDatabaseSchemaDefinition( - databaseSchemaDefinition, - namespace.namespaceName(), - typesInfo - ); - } + generateNamespaceStatement( + namespaceStatement, + namespace.namespaceName(), + typesInfo + ); } } } + private void generateNamespaceStatement( + TypedNamespaceStatementNode namespaceStatement, + NamespaceName namespaceName, + TypesInfo typesInfo + ) throws IOException { + switch (namespaceStatement) { + case TypedDatabaseSchemaDefinitionNode databaseSchemaDefinition -> + generateDatabaseSchemaDefinition( + databaseSchemaDefinition, + namespaceName, + typesInfo + ); + + case TypedEnumDefinitionNode _ -> { + } + + case TypedNativeTypeDefinitionNode _ -> { + } + + case TypedQueryDefinitionNode queryDefinition -> { + generateQueryDefinition( + queryDefinition, + namespaceName, + typesInfo + ); + } + + case TypedStructDefinitionNode _ -> { + } + + case TypedSumDefinitionNode _ -> { + } + } + } + + @Override + public List<Stripper> strippers() { + return List.of(SqlWriter.stripper(this.outputPath)); + } + private void generateDatabaseSchemaDefinition( TypedDatabaseSchemaDefinitionNode databaseSchemaDefinition, NamespaceName namespaceName, @@ -104,6 +140,17 @@ public class SqlScriptsGenerator implements Generator { }; } + private void generateQueryDefinition( + TypedQueryDefinitionNode queryDefinition, + NamespaceName namespaceName, + TypesInfo typesInfo + ) throws IOException { + var sqlQuery = this.sqlGenerator.generateQueryDefinition(queryDefinition, typesInfo); + var sqlScript = new SqlScript(List.of(sqlQuery)); + + write(namespaceName, queryDefinition.name(), sqlScript); + } + private void write( NamespaceName namespaceName, String schemaName, 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..7f0c17a 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) { @@ -61,6 +68,10 @@ public class SqlWriter { case SqlCreateTableStatement createTableStatement -> { writeCreateTableStatement(createTableStatement); } + + case SqlSelectStatement selectStatement -> { + writeSelectStatement(selectStatement); + } } } @@ -97,6 +108,43 @@ public class SqlWriter { this.writeIdentifier(column.typeName()); } + private void writeSelectStatement(SqlSelectStatement selectStatement) throws IOException { + this.writer.write("SELECT"); + this.writer.newLine(); + this.writer.indent(); + + writeWithSeparator( + selectStatement.columns(), + column -> { + this.writeExpression(column.expression()); + this.writer.write(" AS "); + this.writeIdentifier(column.alias()); + }, + () -> { + this.writer.write(","); + this.writer.newLine(); + } + ); + + this.writer.newLine(); + this.writer.dedent(); + this.writer.write("FROM "); + this.writeIdentifier(selectStatement.from()); + + if (!selectStatement.orderBy().isEmpty()) { + this.writer.newLine(); + this.writer.write("ORDER BY "); + + writeWithSeparator( + selectStatement.orderBy(), + orderingTerm -> this.writeExpression(orderingTerm.expression()), + () -> this.writer.write(", ") + ); + } + + this.writer.write(";"); + } + // == Table constraints == void writeTableConstraint(SqlTableConstraint tableConstraint) throws IOException { @@ -117,6 +165,28 @@ public class SqlWriter { this.writer.write(")"); } + // == Expressions == + + void writeExpression(SqlExpression expression) throws IOException { + switch (expression) { + case SqlIntLiteral intLiteral -> { + this.writeIntLiteral(intLiteral); + } + + case SqlRef ref -> { + this.writeRef(ref); + } + } + } + + private void writeIntLiteral(SqlIntLiteral intLiteral) throws IOException { + this.writer.write(Long.toString(intLiteral.value())); + } + + private void writeRef(SqlRef ref) throws IOException { + this.writeIdentifier(ref.name()); + } + // == Identifiers == private void writeIdentifier(SqlIdentifier name) throws IOException { diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlExpression.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlExpression.java new file mode 100644 index 0000000..8479160 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlExpression.java @@ -0,0 +1,18 @@ +// Generated by hobgoblin. + +package org.zwobble.hobgoblin.compiler.output.lang.sql.ast; + +// Custom area start: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlExpression imports +// Custom area end: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlExpression imports + +public sealed interface SqlExpression permits org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIntLiteral, org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlRef { + public interface Builder { + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlExpression build(); + + // Custom area start: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlExpression.Builder body + // Custom area end: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlExpression.Builder body + } + + // Custom area start: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlExpression body + // Custom area end: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlExpression body +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlIntLiteral.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlIntLiteral.java new file mode 100644 index 0000000..8a6c3a4 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlIntLiteral.java @@ -0,0 +1,32 @@ +// Generated by hobgoblin. + +package org.zwobble.hobgoblin.compiler.output.lang.sql.ast; + +// Custom area start: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIntLiteral imports +// Custom area end: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIntLiteral imports + +public record SqlIntLiteral( + long value +) implements org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlExpression { + public static org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIntLiteral.Builder arbitrary() { + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIntLiteral.Builder(0); + } + + public record Builder( + long value + ) implements org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlExpression.Builder { + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIntLiteral build() { + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIntLiteral(value); + } + + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIntLiteral.Builder withValue(long value) { + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIntLiteral.Builder(value); + } + + // Custom area start: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIntLiteral.Builder body + // Custom area end: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIntLiteral.Builder body + } + + // Custom area start: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIntLiteral body + // Custom area end: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIntLiteral body +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlOrderingTerm.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlOrderingTerm.java new file mode 100644 index 0000000..80ca2e6 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlOrderingTerm.java @@ -0,0 +1,36 @@ +// Generated by hobgoblin. + +package org.zwobble.hobgoblin.compiler.output.lang.sql.ast; + +// Custom area start: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlOrderingTerm imports +// Custom area end: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlOrderingTerm imports + +public record SqlOrderingTerm( + org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlExpression expression +) { + public static org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlOrderingTerm.Builder arbitrary() { + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlOrderingTerm.Builder(org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIntLiteral.arbitrary().build()); + } + + public record Builder( + org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlExpression expression + ) { + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlOrderingTerm build() { + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlOrderingTerm(expression); + } + + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlOrderingTerm.Builder withExpression(org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlExpression expression) { + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlOrderingTerm.Builder(expression); + } + + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlOrderingTerm.Builder withExpression(org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlExpression.Builder expression) { + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlOrderingTerm.Builder(expression.build()); + } + + // Custom area start: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlOrderingTerm.Builder body + // Custom area end: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlOrderingTerm.Builder body + } + + // Custom area start: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlOrderingTerm body + // Custom area end: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlOrderingTerm body +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlRef.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlRef.java new file mode 100644 index 0000000..156e6ab --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlRef.java @@ -0,0 +1,36 @@ +// Generated by hobgoblin. + +package org.zwobble.hobgoblin.compiler.output.lang.sql.ast; + +// Custom area start: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlRef imports +// Custom area end: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlRef imports + +public record SqlRef( + org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier name +) implements org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlExpression { + public static org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlRef.Builder arbitrary() { + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlRef.Builder(org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier.arbitrary().build()); + } + + public record Builder( + org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier name + ) implements org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlExpression.Builder { + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlRef build() { + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlRef(name); + } + + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlRef.Builder withName(org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier name) { + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlRef.Builder(name); + } + + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlRef.Builder withName(org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier.Builder name) { + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlRef.Builder(name.build()); + } + + // Custom area start: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlRef.Builder body + // Custom area end: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlRef.Builder body + } + + // Custom area start: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlRef body + // Custom area end: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlRef body +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlResultColumn.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlResultColumn.java new file mode 100644 index 0000000..26516b0 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlResultColumn.java @@ -0,0 +1,46 @@ +// Generated by hobgoblin. + +package org.zwobble.hobgoblin.compiler.output.lang.sql.ast; + +// Custom area start: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlResultColumn imports +// Custom area end: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlResultColumn imports + +public record SqlResultColumn( + org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlExpression expression, + org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier alias +) { + public static org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlResultColumn.Builder arbitrary() { + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlResultColumn.Builder(org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIntLiteral.arbitrary().build(), org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier.arbitrary().build()); + } + + public record Builder( + org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlExpression expression, + org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier alias + ) { + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlResultColumn build() { + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlResultColumn(expression, alias); + } + + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlResultColumn.Builder withExpression(org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlExpression expression) { + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlResultColumn.Builder(expression, alias); + } + + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlResultColumn.Builder withExpression(org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlExpression.Builder expression) { + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlResultColumn.Builder(expression.build(), alias); + } + + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlResultColumn.Builder withAlias(org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier alias) { + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlResultColumn.Builder(expression, alias); + } + + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlResultColumn.Builder withAlias(org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier.Builder alias) { + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlResultColumn.Builder(expression, alias.build()); + } + + // Custom area start: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlResultColumn.Builder body + // Custom area end: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlResultColumn.Builder body + } + + // Custom area start: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlResultColumn body + // Custom area end: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlResultColumn body +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlSelectStatement.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlSelectStatement.java new file mode 100644 index 0000000..8bd29a2 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlSelectStatement.java @@ -0,0 +1,72 @@ +// Generated by hobgoblin. + +package org.zwobble.hobgoblin.compiler.output.lang.sql.ast; + +// Custom area start: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlSelectStatement imports +// Custom area end: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlSelectStatement imports + +public record SqlSelectStatement( + java.util.List<org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlResultColumn> columns, + org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier from, + java.util.List<org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlOrderingTerm> orderBy +) implements org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlStatement { + public static org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlSelectStatement.Builder arbitrary() { + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlSelectStatement.Builder(java.util.List.of(), org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier.arbitrary().build(), java.util.List.of()); + } + + public record Builder( + java.util.List<org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlResultColumn> columns, + org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier from, + java.util.List<org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlOrderingTerm> orderBy + ) implements org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlStatement.Builder { + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlSelectStatement build() { + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlSelectStatement(columns, from, orderBy); + } + + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlSelectStatement.Builder withColumns(java.util.List<org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlResultColumn> columns) { + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlSelectStatement.Builder(columns, from, orderBy); + } + + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlSelectStatement.Builder addColumn(org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlResultColumn column) { + var columns = new java.util.ArrayList<org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlResultColumn>(this.columns); + columns.add(column); + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlSelectStatement.Builder(columns, from, orderBy); + } + + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlSelectStatement.Builder addColumn(org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlResultColumn.Builder column) { + var columns = new java.util.ArrayList<org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlResultColumn>(this.columns); + columns.add(column.build()); + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlSelectStatement.Builder(columns, from, orderBy); + } + + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlSelectStatement.Builder withFrom(org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier from) { + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlSelectStatement.Builder(columns, from, orderBy); + } + + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlSelectStatement.Builder withFrom(org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier.Builder from) { + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlSelectStatement.Builder(columns, from.build(), orderBy); + } + + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlSelectStatement.Builder withOrderBy(java.util.List<org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlOrderingTerm> orderBy) { + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlSelectStatement.Builder(columns, from, orderBy); + } + + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlSelectStatement.Builder addOrderByElement(org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlOrderingTerm orderByElement) { + var orderBy = new java.util.ArrayList<org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlOrderingTerm>(this.orderBy); + orderBy.add(orderByElement); + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlSelectStatement.Builder(columns, from, orderBy); + } + + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlSelectStatement.Builder addOrderByElement(org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlOrderingTerm.Builder orderByElement) { + var orderBy = new java.util.ArrayList<org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlOrderingTerm>(this.orderBy); + orderBy.add(orderByElement.build()); + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlSelectStatement.Builder(columns, from, orderBy); + } + + // Custom area start: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlSelectStatement.Builder body + // Custom area end: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlSelectStatement.Builder body + } + + // Custom area start: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlSelectStatement body + // Custom area end: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlSelectStatement body +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlStatement.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlStatement.java index 0f90dc1..a6d4ab2 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlStatement.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlStatement.java @@ -5,7 +5,7 @@ package org.zwobble.hobgoblin.compiler.output.lang.sql.ast; // Custom area start: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlStatement imports // Custom area end: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlStatement imports -public sealed interface SqlStatement permits org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement { +public sealed interface SqlStatement permits org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement, org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlSelectStatement { public interface Builder { public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlStatement build(); 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..13c38db --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/parser/OperatorPrecedence.java @@ -0,0 +1,6 @@ +package org.zwobble.hobgoblin.compiler.parser; + +enum OperatorPrecedence { + CALL, + COMPARE, +} 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..b4bb07d 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/parser/Parser.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/parser/Parser.java @@ -9,11 +9,15 @@ import org.zwobble.hobgoblin.compiler.types.QualifiedTypeName; import org.zwobble.sourcetext.SourcePosition; import org.zwobble.sourcetext.SourceText; +import java.math.BigDecimal; 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() { @@ -71,7 +75,7 @@ public class Parser { ); tokens.skip(TokenType.SYMBOL_BRACE_CLOSE); - tokens.skip(TokenType.KEYWORD_FROM); + tokens.skip(TokenType.IDENTIFIER, "from"); var isSibling = tokens.trySkip(TokenType.SYMBOL_DOT); @@ -113,6 +117,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 +245,39 @@ 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.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, + statements, + docComment, + source + ); + } + private static UntypedStructDefinitionNode parseStructDefinition( TokenIterator tokens, DocComment docComment @@ -371,7 +410,7 @@ public class Parser { tokens.skip(TokenType.SYMBOL_SEMICOLON); tokens.skip(TokenType.IDENTIFIER, "primaryKey"); - var primaryKey = parseIdentifier(tokens); + var primaryKey = parseTypeLevelReference(tokens); tokens.skip(TokenType.SYMBOL_SEMICOLON); tokens.skip(TokenType.SYMBOL_BRACE_CLOSE); @@ -415,6 +454,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( @@ -442,6 +494,10 @@ public class Parser { } private static UntypedTypeLevelReferenceNode parsePrimaryTypeLevelExpression(TokenIterator tokens) { + return parseTypeLevelReference(tokens); + } + + private static UntypedTypeLevelReferenceNode parseTypeLevelReference(TokenIterator tokens) { var start = tokens.startPosition(); var name = parseIdentifier(tokens); @@ -455,6 +511,235 @@ 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.NUMBER)) { + return parseNumberLiteral(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 UntypedNumberLiteralNode parseNumberLiteral(TokenIterator tokens) { + var start = tokens.startPosition(); + + var valueToken = tokens.next(TokenType.NUMBER); + var value = new BigDecimal(valueToken.charSequence().toString()); + + var end = tokens.endPosition(); + var source = createSource(start, end); + + return new UntypedNumberLiteralNode(value, 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 class BinaryOperationParser implements OperationParser<OperatorPrecedence, UntypedExpressionNode> { + private final UntypedBinaryOperator operator; + private final OperatorPrecedence precedence; + private final TokenType operatorTokenType; + + public BinaryOperationParser( + UntypedBinaryOperator operator, + OperatorPrecedence precedence, + TokenType operatorTokenType + ) { + this.operator = operator; + this.precedence = precedence; + this.operatorTokenType = operatorTokenType; + } + + @Override + public OperatorPrecedence precedence() { + return precedence; + } + + @Override + public List<TokenType> operatorTokenTypes() { + return List.of(operatorTokenType); + } + + @Override + public UntypedExpressionNode parse(SourcePosition start, UntypedExpressionNode left, TokenIterator tokens) { + tokens.skip(operatorTokenType); + + var right = parseExpression(tokens, Optional.of(precedence)); + + var end = tokens.endPosition(); + var source = createSource(start, end); + + return new UntypedBinaryOperationNode(operator, left, right, 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 BinaryOperationParser EQUALS_OPERATION_PARSER = new BinaryOperationParser( + UntypedBinaryOperator.EQUALS, + OperatorPrecedence.COMPARE, + TokenType.SYMBOL_EQUALS_EQUALS + ); + + private static final Map<TokenType, OperationParser<OperatorPrecedence, UntypedExpressionNode>> OPERATION_PARSERS = Stream.of( + CALL_PARSER, + EQUALS_OPERATION_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..5896d6f 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/parser/TokenType.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/parser/TokenType.java @@ -4,11 +4,11 @@ enum TokenType { DOC_COMMENT, END, IDENTIFIER, + NUMBER, WHITESPACE, KEYWORD_ENUM, KEYWORD_FIELD, - KEYWORD_FROM, KEYWORD_IMPORT, KEYWORD_NATIVE, KEYWORD_STRUCT, @@ -19,8 +19,11 @@ enum TokenType { SYMBOL_BRACE_CLOSE, SYMBOL_COLON, SYMBOL_COMMA, + SYMBOL_DOLLAR, SYMBOL_DOT, SYMBOL_DOT_DOT, + SYMBOL_EQUALS_EQUALS, + 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..b36ca12 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/parser/Tokenizer.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/parser/Tokenizer.java @@ -55,6 +55,11 @@ class Tokenizer { return identifierOrKeyword; } + var number = tokenizeNumber(iterator); + if (number.isPresent()) { + return number; + } + var docComment = tokenizeDocComment(iterator); if (docComment.isPresent()) { return docComment; @@ -126,8 +131,6 @@ class Tokenizer { tokenType = TokenType.KEYWORD_ENUM; } else if (CharSequence.compare(sourceRange.charSequence(), "field") == 0) { tokenType = TokenType.KEYWORD_FIELD; - } else if (CharSequence.compare(sourceRange.charSequence(), "from") == 0) { - tokenType = TokenType.KEYWORD_FROM; } else if (CharSequence.compare(sourceRange.charSequence(), "import") == 0) { tokenType = TokenType.KEYWORD_IMPORT; } else if (CharSequence.compare(sourceRange.charSequence(), "native") == 0) { @@ -146,6 +149,30 @@ class Tokenizer { return Optional.of(token); } + private static Optional<Token> tokenizeNumber(CharacterIterator iterator) { + var firstChar = iterator.peek(); + if (!(firstChar >= '1' && firstChar <= '9')) { + return Optional.empty(); + } + + var start = iterator.position(); + + while (true) { + var nextChar = iterator.peek(); + if (!(nextChar >= '0' && nextChar <= '9')) { + if (Character.isAlphabetic(nextChar)) { + throw new ParseError("number must contain only digits", iterator.characterSourceRange()); + } + + var end = iterator.position(); + var token = new Token(TokenType.NUMBER, start.to(end)); + return Optional.of(token); + } + + iterator.skip(); + } + } + private static Optional<Token> tokenizeSymbol(CharacterIterator iterator) { TokenType tokenType; var start = iterator.position(); @@ -154,6 +181,14 @@ 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 if ("==".contentEquals(iterator.peekSequence(2))) { + tokenType = TokenType.SYMBOL_EQUALS_EQUALS; + iterator.skip(); + iterator.skip(); } else { switch (iterator.peek()) { case '{': @@ -176,6 +211,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..c3f664c 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,39 @@ 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 databaseSchema = new DatabaseSchema(context.namespaceName(), untyped.name()); + var databaseSchemaInfo = new DatabaseSchemaInfo(new LinkedHashMap<>()); + + var typedBody = untyped.body().stream() + .map(statement -> typeCheckDatabaseSchemaStatement( + statement, + databaseSchema, + databaseSchemaInfo, + context + )) + .toList(); + + context.defineDatabaseSchema(databaseSchema, databaseSchemaInfo); + return new TypedDatabaseSchemaDefinitionNode( untyped.name(), - untyped.body().stream() - .map(statement -> typeCheckDatabaseSchemaStatement(statement, context)) - .toList(), + typedBody, untyped.docComment(), untyped.source() ); @@ -247,6 +285,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(), + new RelationTable(table), + untyped.docComment(), + untyped.source() + ); + } + private static TypedStructDefinitionNode defineStructDefinition( UntypedStructDefinitionNode untyped, TypeCheckerNamespaceContext context @@ -455,18 +508,29 @@ public class TypeChecker { } } + // == Database schema statements == + static TypedDatabaseSchemaStatementNode typeCheckDatabaseSchemaStatement( UntypedDatabaseSchemaStatementNode statement, + DatabaseSchema databaseSchema, + DatabaseSchemaInfo databaseSchemaInfo, TypeCheckerNamespaceContext context ) { return switch (statement) { case UntypedTableDefinitionNode untypedTableDefinition -> - typeCheckTableDefinition(untypedTableDefinition, context); + typeCheckTableDefinition( + untypedTableDefinition, + databaseSchema, + databaseSchemaInfo, + context + ); }; } private static TypedTableDefinitionNode typeCheckTableDefinition( UntypedTableDefinitionNode untyped, + DatabaseSchema databaseSchema, + DatabaseSchemaInfo databaseSchemaInfo, TypeCheckerNamespaceContext context ) { var rowTypeTypedNode = typeCheckMetaType(untyped.rowType(), context); @@ -479,15 +543,26 @@ public class TypeChecker { ); } + // In principle, we should check that fields is non-empty. In practice, + // we implicitly check this by requiring a primary key. var fields = context.fieldsOf(rowType).orElse(List.of()); + var primaryKeyField = fields.stream() - .filter(field -> field.name().equals(untyped.primaryKey())) + .filter(field -> field.name().equals(untyped.primaryKey().name())) .findFirst(); if (primaryKeyField.isEmpty()) { - // TODO: more precise source. - throw new NoSuchFieldError(rowType, untyped.primaryKey(), untyped.source()); + throw new NoSuchFieldError( + rowType, + untyped.primaryKey().name(), + untyped.primaryKey().source() + ); } + var table = new Table(databaseSchema, untyped.name()); + var tableInfo = new TableInfo(table, rowType, primaryKeyField.get()); + + databaseSchemaInfo.tables().put(untyped.name(), tableInfo); + return new TypedTableDefinitionNode( untyped.name(), rowType, @@ -497,6 +572,8 @@ public class TypeChecker { ); } + // == Type-level expressions == + static TypedTypeLevelExpressionNode<? extends TypeLevelValue> typeCheckTypeLevelExpression( UntypedTypeLevelExpressionNode untyped, TypeCheckerNamespaceContext context @@ -582,7 +659,7 @@ public class TypeChecker { // TODO: handle not a type-level value if (!(type instanceof TypeLevelValueType(TypeLevelValue value))) { - throw new UnexpectedTypeError(new TypeSet.MetaType(), type, source); + throw new UnexpectedTypeError(new TypeSet.TypeLevelValue(), type, source); } return value; @@ -602,4 +679,91 @@ 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 == + + static TypeLevelValue evalExpression( + UntypedExpressionNode expression, + TypeCheckerNamespaceContext context + ) { + switch (expression) { + case UntypedBinaryOperationNode _ -> { + throw new UnsupportedOperationException("TODO"); + } + case UntypedCallNode _ -> { + throw new UnsupportedOperationException("TODO"); + } + case UntypedFunctionExpressionNode _ -> { + throw new UnsupportedOperationException("TODO"); + } + case UntypedMemberAccessNode memberAccess -> { + return evalMemberAccess(memberAccess, context); + } + case UntypedNumberLiteralNode numberLiteral -> { + return evalNumberLiteral(numberLiteral); + } + case UntypedReferenceNode reference -> { + return lookupTypeLevelValue(reference.name(), reference.source(), context); + } + } + } + + private static TypeLevelValue evalMemberAccess( + UntypedMemberAccessNode memberAccess, + TypeCheckerNamespaceContext context + ) { + var receiver = evalExpression(memberAccess.receiver(), context); + switch (receiver) { + case DatabaseSchema databaseSchema -> { + var schemaInfo = context.databaseSchemaInfo(databaseSchema); + var tableInfo = schemaInfo.tables().get(memberAccess.memberName()); + if (tableInfo != null) { + return tableInfo.table(); + } + } + + case Table table -> { + switch (memberAccess.memberName()) { + case "where": + return new RelationMethod(new RelationTable(table), "where"); + + default: + break; + } + } + + case ConstantNumber _, Type _, TypeConstructor<?> _, RelationMethod _ -> { + } + } + + throw new NoSuchMemberError( + new TypeLevelValueType(receiver), + memberAccess.memberName(), + memberAccess.source() + ); + } + + private static TypeLevelValue evalNumberLiteral( + UntypedNumberLiteralNode numberLiteral + ) { + return new ConstantNumber(numberLiteral.value()); + } } 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..4a82c05 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,17 @@ public class TypeCheckerNamespaceContext { return Optional.ofNullable(this.variables.get(name)); } + public void defineDatabaseSchema( + DatabaseSchema databaseSchema, + DatabaseSchemaInfo databaseSchemaInfo + ) { + this.typesInfo.defineDatabaseSchema(databaseSchema, databaseSchemaInfo); + } + + public DatabaseSchemaInfo databaseSchemaInfo(DatabaseSchema databaseSchema) { + return this.typesInfo.databaseSchemaInfo(databaseSchema); + } + 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/typechecker/errors/NoSuchMemberError.java b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/errors/NoSuchMemberError.java new file mode 100644 index 0000000..b2b1d55 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/errors/NoSuchMemberError.java @@ -0,0 +1,24 @@ +package org.zwobble.hobgoblin.compiler.typechecker.errors; + +import org.zwobble.hobgoblin.compiler.errors.SourceError; +import org.zwobble.hobgoblin.compiler.sources.Source; +import org.zwobble.hobgoblin.compiler.types.Type; + +public class NoSuchMemberError extends SourceError { + private final Type type; + private final String memberName; + + public NoSuchMemberError(Type type, String memberName, Source source) { + super(type.describe() + " does not have a member named " + memberName, source); + this.type = type; + this.memberName = memberName; + } + + public Type type() { + return type; + } + + public String memberName() { + return memberName; + } +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/types/ConstantNumber.java b/src/main/java/org/zwobble/hobgoblin/compiler/types/ConstantNumber.java new file mode 100644 index 0000000..bd16d81 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/types/ConstantNumber.java @@ -0,0 +1,12 @@ +package org.zwobble.hobgoblin.compiler.types; + +import java.math.BigDecimal; + +public record ConstantNumber( + BigDecimal value +) implements TypeLevelValue { + @Override + public String describe() { + return value.toString(); + } +} 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/RelationMethod.java b/src/main/java/org/zwobble/hobgoblin/compiler/types/RelationMethod.java new file mode 100644 index 0000000..87ba7fa --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/types/RelationMethod.java @@ -0,0 +1,10 @@ +package org.zwobble.hobgoblin.compiler.types; + +import org.zwobble.hobgoblin.compiler.ast.typed.Relation; + +public record RelationMethod(Relation relation, String name) implements TypeLevelValue { + @Override + public String describe() { + return name; + } +} 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..b991b54 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/types/TableInfo.java @@ -0,0 +1,8 @@ +package org.zwobble.hobgoblin.compiler.types; + +public record TableInfo( + Table table, + 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..e0f7042 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 ConstantNumber, DatabaseSchema, RelationMethod, Table, Type, TypeConstructor { String describe(); } diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/types/TypeSet.java b/src/main/java/org/zwobble/hobgoblin/compiler/types/TypeSet.java index c3896d9..3a64b85 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/types/TypeSet.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/types/TypeSet.java @@ -23,4 +23,11 @@ public sealed interface TypeSet { return "type constructor"; } } + + record TypeLevelValue() implements TypeSet { + @Override + public String describe() { + return "type-level value"; + } + } } 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..756f3bf 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,16 @@ 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 relationMethod(RelationMethod method) { + return new TypeLevelValueType(method); + } + + public static Type table(Table table) { + return new TypeLevelValueType(table); + } } |
