From 158ebdbc74e74894a32be9c8908da4b068326b67 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Sun, 1 Nov 2026 21:48:11 +0000 Subject: Read tables as members from database schema --- .../compiler/typechecker/TypeChecker.java | 54 ++++++++++++++++++---- .../typechecker/TypeCheckerNamespaceContext.java | 4 ++ .../typechecker/errors/NoSuchMemberError.java | 24 ++++++++++ .../hobgoblin/compiler/types/TableInfo.java | 1 + 4 files changed, 74 insertions(+), 9 deletions(-) create mode 100644 src/main/java/org/zwobble/hobgoblin/compiler/typechecker/errors/NoSuchMemberError.java (limited to 'src/main/java') 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 d73c245..da83e6f 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeChecker.java @@ -163,16 +163,19 @@ public class TypeChecker { 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, databaseSchemaInfo, context)) + .map(statement -> typeCheckDatabaseSchemaStatement( + statement, + databaseSchema, + databaseSchemaInfo, + context + )) .toList(); - context.defineDatabaseSchema( - new DatabaseSchema(context.namespaceName(), untyped.name()), - databaseSchemaInfo - ); + context.defineDatabaseSchema(databaseSchema, databaseSchemaInfo); return new TypedDatabaseSchemaDefinitionNode( untyped.name(), @@ -509,17 +512,24 @@ public class TypeChecker { static TypedDatabaseSchemaStatementNode typeCheckDatabaseSchemaStatement( UntypedDatabaseSchemaStatementNode statement, + DatabaseSchema databaseSchema, DatabaseSchemaInfo databaseSchemaInfo, TypeCheckerNamespaceContext context ) { return switch (statement) { case UntypedTableDefinitionNode untypedTableDefinition -> - typeCheckTableDefinition(untypedTableDefinition, databaseSchemaInfo, context); + typeCheckTableDefinition( + untypedTableDefinition, + databaseSchema, + databaseSchemaInfo, + context + ); }; } private static TypedTableDefinitionNode typeCheckTableDefinition( UntypedTableDefinitionNode untyped, + DatabaseSchema databaseSchema, DatabaseSchemaInfo databaseSchemaInfo, TypeCheckerNamespaceContext context ) { @@ -542,7 +552,8 @@ public class TypeChecker { throw new NoSuchFieldError(rowType, untyped.primaryKey(), untyped.source()); } - var tableInfo = new TableInfo(rowType, primaryKeyField.get()); + var table = new Table(databaseSchema, untyped.name()); + var tableInfo = new TableInfo(table, rowType, primaryKeyField.get()); databaseSchemaInfo.tables().put(untyped.name(), tableInfo); @@ -694,12 +705,37 @@ public class TypeChecker { case UntypedFunctionExpressionNode _ -> { throw new UnsupportedOperationException("TODO"); } - case UntypedMemberAccessNode _ -> { - throw new UnsupportedOperationException("TODO"); + case UntypedMemberAccessNode memberAccess -> { + return evalMemberAccess(memberAccess, context); } 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 _, Type _, TypeConstructor _ -> { + } + } + + throw new NoSuchMemberError( + new TypeLevelValueType(receiver), + memberAccess.memberName(), + memberAccess.source() + ); + } } 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 b18769d..4a82c05 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerNamespaceContext.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/typechecker/TypeCheckerNamespaceContext.java @@ -64,6 +64,10 @@ public class TypeCheckerNamespaceContext { this.typesInfo.defineDatabaseSchema(databaseSchema, databaseSchemaInfo); } + public DatabaseSchemaInfo databaseSchemaInfo(DatabaseSchema databaseSchema) { + return this.typesInfo.databaseSchemaInfo(databaseSchema); + } + public void defineEnumType(EnumType enumType, List enumVariants) { this.typesInfo.defineEnumType(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/TableInfo.java b/src/main/java/org/zwobble/hobgoblin/compiler/types/TableInfo.java index 6632e51..b991b54 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/types/TableInfo.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/types/TableInfo.java @@ -1,6 +1,7 @@ package org.zwobble.hobgoblin.compiler.types; public record TableInfo( + Table table, SimpleStructType rowType, Field primaryKey ) { -- cgit v1.2.3