diff --git a/src/qir/driver/sql/QIRSQLTypeSystemVisitor.java b/src/qir/driver/sql/QIRSQLTypeSystem.java similarity index 90% rename from src/qir/driver/sql/QIRSQLTypeSystemVisitor.java rename to src/qir/driver/sql/QIRSQLTypeSystem.java index 32aacbe490b289f4f9a183be8013882b51add40b..9dd6925b9842ea5a9942670649a62e8973b7763f 100644 --- a/src/qir/driver/sql/QIRSQLTypeSystemVisitor.java +++ b/src/qir/driver/sql/QIRSQLTypeSystem.java @@ -25,21 +25,23 @@ import qir.types.QIRStringType; import qir.types.QIRType; import qir.typing.QIRSpecificTypeSystem; import qir.typing.QIRTypeErrorException; -import qir.typing.QIRTypeSystemVisitor; -public class QIRSQLTypeSystemVisitor extends QIRSpecificTypeSystem { - public QIRSQLTypeSystemVisitor() { +/** + * The {@link QIRSpecificTypeSystem} for SQL. + */ +public class QIRSQLTypeSystem extends QIRSpecificTypeSystem { + /** + * The {@link QIRSQLTypeSystem} can only have flat records (records containing constants), and + * lists can only contain flat records. + */ + public QIRSQLTypeSystem() { this(QIRRecordType.anyRestrictedTo(QIRConstantType.ANY)); } - private QIRSQLTypeSystemVisitor(final QIRRecordType anyRelationalRecord) { + private QIRSQLTypeSystem(final QIRRecordType anyRelationalRecord) { super(anyRelationalRecord, new QIRListType(anyRelationalRecord)); } - public QIRSQLTypeSystemVisitor(final QIRRecordType anyRecordType, final QIRListType anyListType, final QIRTypeSystemVisitor toAccept) { - super(anyRecordType, anyListType, toAccept); - } - @Override public final QIRType visit(final QIRProject qirProject) { return visit(qirProject, anyRecordType); diff --git a/src/qir/typing/QIRDefaultTypeSystem.java b/src/qir/typing/QIRDefaultTypeSystem.java new file mode 100644 index 0000000000000000000000000000000000000000..24e7e847a630fb37aebd47d9faa86aac2399aed2 --- /dev/null +++ b/src/qir/typing/QIRDefaultTypeSystem.java @@ -0,0 +1,28 @@ +package qir.typing; + +import qir.types.QIRListType; +import qir.types.QIRRecordType; + +/** + * The default {@link QIRSpecificTypeSystem}. It uses the default rules of + * {@link QIRSpecificTypeSystem}. + */ +public class QIRDefaultTypeSystem extends QIRSpecificTypeSystem { + /** + * The {@link QIRDefaultTypeSystem} is a {@link QIRSpecificTypeSystem} working on any type of + * record and any type of list, and that calls the {@link QIRGenericTypeSystem} on + * subexpressions. + */ + private QIRDefaultTypeSystem() { + super(QIRRecordType.ANY, QIRListType.ANY, QIRGenericTypeSystem.getInstance()); + } + + /** + * The unique representation of the {@link QIRDefaultTypeSystem}. + */ + private static final QIRDefaultTypeSystem instance = new QIRDefaultTypeSystem(); + + public static final QIRDefaultTypeSystem getInstance() { + return instance; + } +} diff --git a/src/qir/typing/QIRDefaultTypeSystemVisitor.java b/src/qir/typing/QIRDefaultTypeSystemVisitor.java deleted file mode 100644 index 2a7f1b43212c2796f0d1f3d9a9a4ca88c3f17cc3..0000000000000000000000000000000000000000 --- a/src/qir/typing/QIRDefaultTypeSystemVisitor.java +++ /dev/null @@ -1,16 +0,0 @@ -package qir.typing; - -import qir.types.QIRListType; -import qir.types.QIRRecordType; - -public class QIRDefaultTypeSystemVisitor extends QIRSpecificTypeSystem { - private QIRDefaultTypeSystemVisitor() { - super(QIRRecordType.ANY, QIRListType.ANY, QIRGenericTypeSystemVisitor.getInstance()); - } - - private static final QIRDefaultTypeSystemVisitor instance = new QIRDefaultTypeSystemVisitor(); - - public static final QIRDefaultTypeSystemVisitor getInstance() { - return instance; - } -} diff --git a/src/qir/typing/QIRGenericTypeSystemVisitor.java b/src/qir/typing/QIRGenericTypeSystem.java similarity index 57% rename from src/qir/typing/QIRGenericTypeSystemVisitor.java rename to src/qir/typing/QIRGenericTypeSystem.java index b75060cd43b9fc2403294e04cec8a92df7f0a412..b3009099b7b2d87b24e5e4d1b3c16b9f152f6dbf 100644 --- a/src/qir/typing/QIRGenericTypeSystemVisitor.java +++ b/src/qir/typing/QIRGenericTypeSystem.java @@ -45,19 +45,30 @@ import qir.ast.operator.QIRProject; import qir.ast.operator.QIRRightJoin; import qir.ast.operator.QIRScan; import qir.ast.operator.QIRSortBy; -import qir.driver.sql.QIRSQLTypeSystemVisitor; +import qir.driver.sql.QIRSQLTypeSystem; import qir.types.QIRType; import qir.util.QIRException; -public final class QIRGenericTypeSystemVisitor extends QIRTypeSystemVisitor { - private static List<Class<? extends QIRSpecificTypeSystem>> specificTypeSystems = Arrays.asList(QIRSQLTypeSystemVisitor.class); +/** + * The generic {@link QIRTypeSystem} of QIR that can type any QIR expression. It makes use of + * {@link QIRSpecificTypeSystem}s as much as possible, then defaults to the + * {@link QIRDefaultTypeSystem}. + */ +public final class QIRGenericTypeSystem extends QIRTypeSystem { + /** + * The registered {@link QIRSpecificTypeSystem}s used by the {@link QIRGenericTypeSystem}. + */ + private static final List<Class<? extends QIRSpecificTypeSystem>> specificTypeSystems = Arrays.asList(QIRSQLTypeSystem.class); - private QIRGenericTypeSystemVisitor() { + private QIRGenericTypeSystem() { } - private static final QIRGenericTypeSystemVisitor instance = new QIRGenericTypeSystemVisitor(); + /** + * The unique representation of the {@link QIRGenericTypeSystem}. + */ + private static final QIRGenericTypeSystem instance = new QIRGenericTypeSystem(); - public static final QIRGenericTypeSystemVisitor getInstance() { + public static final QIRGenericTypeSystem getInstance() { return instance; } @@ -70,173 +81,173 @@ public final class QIRGenericTypeSystemVisitor extends QIRTypeSystemVisitor { throw new QIRException("Internal error: " + specificTypeSystem.getName() + " could not be instantiated."); } try { - return expr.setType(expr.accept(QIRDefaultTypeSystemVisitor.getInstance()), QIRDefaultTypeSystemVisitor.class); + return expr.setType(expr.accept(QIRDefaultTypeSystem.getInstance()), QIRDefaultTypeSystem.class); } catch (final QIRTypeErrorException e) { throw new QIRException("No type system could type " + expr); } } - public QIRType visit(QIRProject qirProject) { + public QIRType visit(final QIRProject qirProject) { return tryTyping(qirProject); } - public QIRType visit(QIRScan qirScan) { + public QIRType visit(final QIRScan qirScan) { return tryTyping(qirScan); } - public QIRType visit(QIRFilter qirFilter) { + public QIRType visit(final QIRFilter qirFilter) { return tryTyping(qirFilter); } - public QIRType visit(QIRGroupBy qirGroupBy) { + public QIRType visit(final QIRGroupBy qirGroupBy) { return tryTyping(qirGroupBy); } - public QIRType visit(QIRSortBy qirSortBy) { + public QIRType visit(final QIRSortBy qirSortBy) { return tryTyping(qirSortBy); } - public QIRType visit(QIRJoin qirJoin) { + public QIRType visit(final QIRJoin qirJoin) { return tryTyping(qirJoin); } - public QIRType visit(QIRLeftJoin qirJoin) { + public QIRType visit(final QIRLeftJoin qirJoin) { return tryTyping(qirJoin); } - public QIRType visit(QIRRightJoin qirJoin) { + public QIRType visit(final QIRRightJoin qirJoin) { return tryTyping(qirJoin); } - public QIRType visit(QIRLimit qirLimit) { + public QIRType visit(final QIRLimit qirLimit) { return tryTyping(qirLimit); } - public <DBRepr> QIRType visit(QIRDBNode<DBRepr> qirDBNode) { + public <DBRepr> QIRType visit(final QIRDBNode<DBRepr> qirDBNode) { return tryTyping(qirDBNode); } - public QIRType visit(QIRExternal qirExternal) { + public QIRType visit(final QIRExternal qirExternal) { return tryTyping(qirExternal); } - public QIRType visit(QIRVariable qirVariable) { + public QIRType visit(final QIRVariable qirVariable) { return tryTyping(qirVariable); } - public QIRType visit(QIRLambda qirLambda) { + public QIRType visit(final QIRLambda qirLambda) { return tryTyping(qirLambda); } - public QIRType visit(QIRApply qirApply) { + public QIRType visit(final QIRApply qirApply) { return tryTyping(qirApply); } - public QIRType visit(QIRIf qirIf) { + public QIRType visit(final QIRIf qirIf) { return tryTyping(qirIf); } - public QIRType visit(QIRPlus qirPlus) { + public QIRType visit(final QIRPlus qirPlus) { return tryTyping(qirPlus); } - public QIRType visit(QIRMinus qirMinus) { + public QIRType visit(final QIRMinus qirMinus) { return tryTyping(qirMinus); } - public QIRType visit(QIRStar qirStar) { + public QIRType visit(final QIRStar qirStar) { return tryTyping(qirStar); } - public QIRType visit(QIRDiv qirDiv) { + public QIRType visit(final QIRDiv qirDiv) { return tryTyping(qirDiv); } - public QIRType visit(QIRMod qirMod) { + public QIRType visit(final QIRMod qirMod) { return tryTyping(qirMod); } - public QIRType visit(QIRAnd qirAnd) { + public QIRType visit(final QIRAnd qirAnd) { return tryTyping(qirAnd); } - public QIRType visit(QIROr qirOr) { + public QIRType visit(final QIROr qirOr) { return tryTyping(qirOr); } - public QIRType visit(QIREqual qirEqual) { + public QIRType visit(final QIREqual qirEqual) { return tryTyping(qirEqual); } - public QIRType visit(QIRLowerOrEqual qirLowerOrEqual) { + public QIRType visit(final QIRLowerOrEqual qirLowerOrEqual) { return tryTyping(qirLowerOrEqual); } - public QIRType visit(QIRLowerThan qirLowerThan) { + public QIRType visit(final QIRLowerThan qirLowerThan) { return tryTyping(qirLowerThan); } - public QIRType visit(QIRNot qirNot) { + public QIRType visit(final QIRNot qirNot) { return tryTyping(qirNot); } - public QIRType visit(QIRTable qirTable) { + public QIRType visit(final QIRTable qirTable) { return tryTyping(qirTable); } - public QIRType visit(QIRLnil qirLnil) { + public QIRType visit(final QIRLnil qirLnil) { return tryTyping(qirLnil); } - public QIRType visit(QIRLcons qirLcons) { + public QIRType visit(final QIRLcons qirLcons) { return tryTyping(qirLcons); } - public QIRType visit(QIRLdestr qirLdestr) { + public QIRType visit(final QIRLdestr qirLdestr) { return tryTyping(qirLdestr); } - public QIRType visit(QIRRnil qirTnil) { + public QIRType visit(final QIRRnil qirTnil) { return tryTyping(qirTnil); } - public QIRType visit(QIRRcons qirTcons) { + public QIRType visit(final QIRRcons qirTcons) { return tryTyping(qirTcons); } - public QIRType visit(QIRRdestr qirTdestr) { + public QIRType visit(final QIRRdestr qirTdestr) { return tryTyping(qirTdestr); } - public QIRType visit(QIRString qirString) { + public QIRType visit(final QIRString qirString) { return tryTyping(qirString); } - public QIRType visit(QIRNumber qirNumber) { + public QIRType visit(final QIRNumber qirNumber) { return tryTyping(qirNumber); } - public QIRType visit(QIRBigNumber qirBigNumber) { + public QIRType visit(final QIRBigNumber qirBigNumber) { return tryTyping(qirBigNumber); } - public QIRType visit(QIRDouble qirDouble) { + public QIRType visit(final QIRDouble qirDouble) { return tryTyping(qirDouble); } - public QIRType visit(QIRBoolean qirBoolean) { + public QIRType visit(final QIRBoolean qirBoolean) { return tryTyping(qirBoolean); } - public QIRType visit(QIRNull qirNull) { + public QIRType visit(final QIRNull qirNull) { return tryTyping(qirNull); } - public QIRType visit(QIRExportableTruffleNode qirTruffleNode) { + public QIRType visit(final QIRExportableTruffleNode qirTruffleNode) { return tryTyping(qirTruffleNode); } - public QIRType visit(QIRUnexportableTruffleNode qirTruffleNode) { + public QIRType visit(final QIRUnexportableTruffleNode qirTruffleNode) { return tryTyping(qirTruffleNode); } } diff --git a/src/qir/typing/QIRSpecificTypeSystem.java b/src/qir/typing/QIRSpecificTypeSystem.java index 6b0c6545e290f0a8bcd2adb468b5fe87c0ba4956..6b414310bb68bea8408a02a9f917f19035370c58 100644 --- a/src/qir/typing/QIRSpecificTypeSystem.java +++ b/src/qir/typing/QIRSpecificTypeSystem.java @@ -58,40 +58,113 @@ import qir.types.QIRSomeType; import qir.types.QIRStringType; import qir.types.QIRType; -public abstract class QIRSpecificTypeSystem extends QIRTypeSystemVisitor { +/** + * A {@link QIRSpecificTypeSystem} is a {@link QIRTypeSystem} that types QIR expressions compatible + * with a specific database language. + */ +public abstract class QIRSpecificTypeSystem extends QIRTypeSystem { + /** + * An environment to store the {@link QIRType}s of variables in an expression. + */ protected final Map<String, QIRType> env = new HashMap<>(); + /** + * The generic {@link QIRType} of a record in the language. + */ protected final QIRRecordType anyRecordType; + /** + * The generic {@link QIRType} of a list in the language. + */ protected final QIRListType anyListType; - protected final QIRTypeSystemVisitor toAccept; - + /** + * The {@link QIRTypeSystem} to call recursively on subexpressions. + */ + protected final QIRTypeSystem toAccept; + + /** + * A {@link QIRSpecificTypeSystem} that calls itself recursively on subexpressions. This is the + * most usual type of {@link QIRSpecificTypeSystem}. + * + * @param anyRecordType The generic {@link QIRType} of a record for this + * {@link QIRSpecificTypeSystem}. + * @param anyListType The generic {@link QIRType} of a list for this + * {@link QIRSpecificTypeSystem}. + */ public QIRSpecificTypeSystem(final QIRRecordType anyRecordType, final QIRListType anyListType) { this.anyRecordType = anyRecordType; this.anyListType = anyListType; this.toAccept = this; } - public QIRSpecificTypeSystem(final QIRRecordType anyRecordType, final QIRListType anyListType, final QIRTypeSystemVisitor toAccept) { + /** + * A {@link QIRSpecificTypeSystem} that calls another {@link QIRSpecificTypeSystem} recursively + * on subexpressions. + * + * @param anyRecordType The generic {@link QIRType} of a record for this + * {@link QIRSpecificTypeSystem}. + * @param anyListType The generic {@link QIRType} of a list for this + * {@link QIRSpecificTypeSystem}. + * @param toAccept The {@link QIRTypeSystem} to call recursively on subexpressions. + */ + public QIRSpecificTypeSystem(final QIRRecordType anyRecordType, final QIRListType anyListType, final QIRTypeSystem toAccept) { this.anyRecordType = anyRecordType; this.anyListType = anyListType; this.toAccept = toAccept; } - protected void checkSubtype(final QIRType actual, final QIRType expected) { + /** + * Throws a {@link QIRTypeErrorException} if the actual {@link QIRType} is not a subtype of the + * expected {@link QIRType} in the sense of {@link QIRType#isSubtypeOf(QIRType)}. + * + * @param actual The actual {@link QIRType} of the expression. + * @param expected The expected {@link QIRType} for the expression. + * @throws QIRTypeErrorException The expression thrown if the actual {@link QIRType} is not a + * subtype of the expected {@link QIRType}. + */ + protected void checkSubtype(final QIRType actual, final QIRType expected) throws QIRTypeErrorException { if (!actual.isSubtypeOf(expected)) throw new QIRTypeErrorException(this.getClass(), expected, actual); } + /** + * Returns the actual {@link QIRType} with the type of the expected {@link QIRType} if the + * actual {@link QIRType} is a subtype of the expected {@link QIRType} in the sense of + * {@link QIRType#isSubtypeOf(QIRType)}. + * + * @param actual The actual {@link QIRType} of the expression. + * @param expected The expected {@link QIRType} for the expression. + * @return The actual {@link QIRType} with the type of the expected {@link QIRType}. + */ @SuppressWarnings("unchecked") protected <U extends QIRType> U expectIfSubtype(final QIRType actual, final U expected) { checkSubtype(actual, expected); return (U) (actual instanceof QIRSomeType ? ((QIRSomeType) actual).getInferedType() : actual); } + /** + * Throws a {@link QIRTypeErrorException} if the actual {@link QIRType} and the expected + * {@link QIRType} do not share a common subtype in the sense of + * {@link QIRType#isSubtypeOf(QIRType)}. + * + * @param actual The actual {@link QIRType} of the expression. + * @param expected The expected {@link QIRType} for the expression. + * @throws QIRTypeErrorException The expression thrown if the actual {@link QIRType} and the + * expected {@link QIRType} do not share a common subtype in the sense of + * {@link QIRType#isSubtypeOf(QIRType)}. + */ protected void checkCommonType(final QIRType actual, final QIRType expected) { if (!actual.isSubtypeOf(expected) && !expected.isSubtypeOf(actual)) throw new QIRTypeErrorException(this.getClass(), expected, actual); } + /** + * Returns the actual {@link QIRType} with the type of the expected {@link QIRType} if the + * actual {@link QIRType} and the expected {@link QIRType} share a common subtype in the sense + * of {@link QIRType#isSubtypeOf(QIRType)}. + * + * @param actual The actual {@link QIRType} of the expression. + * @param expected The expected {@link QIRType} for the expression. + * @return The actual {@link QIRType} with the type of the expected {@link QIRType}. + */ protected QIRType expectCommonType(final QIRType actual, final QIRType expected) { if (actual.isSubtypeOf(expected)) return expected; diff --git a/src/qir/typing/QIRTypeErrorException.java b/src/qir/typing/QIRTypeErrorException.java index b52718adf4d1d0476d8da7bef89a35d18412aaf9..19cabd09df6059041d1f19977d7fc49ce7675909 100644 --- a/src/qir/typing/QIRTypeErrorException.java +++ b/src/qir/typing/QIRTypeErrorException.java @@ -9,26 +9,61 @@ import qir.types.QIRRecordType; import qir.types.QIRType; import qir.util.QIRException; +/** + * An exception that can be thrown by a {@link QIRTypeSystem}. + */ public class QIRTypeErrorException extends QIRException { private static final long serialVersionUID = 2089121923670702478L; - public QIRTypeErrorException(final Class<?> typer, final QIRType expected, final QIRType actual) { + /** + * A mismatch between an expected type and the actual type of an expression. + * + * @param typer The instance of {@link QIRTypeSystem} throwing the exception. + * @param expected The expected type for the expression. + * @param actual The actual type of the expression. + */ + public QIRTypeErrorException(final Class<? extends QIRTypeSystem> typer, final QIRType expected, final QIRType actual) { super(typer.getName() + " type error. Expected: " + expected + ", got: " + actual); } - public QIRTypeErrorException(final Class<?> typer, final QIRType[] expected, final QIRType actual) { + /** + * A mismatch between possible expected types and the actual type of an expression. + * + * @param typer The instance of {@link QIRTypeSystem} throwing the exception. + * @param expected The possible expected types for the expression. + * @param actual The actual type of the expression. + */ + public QIRTypeErrorException(final Class<? extends QIRTypeSystem> typer, final QIRType[] expected, final QIRType actual) { super(typer.getName() + " type error. Expected: " + Arrays.stream(expected).map(Object::toString).collect(Collectors.joining(" or ")) + ", got: " + actual); } - public QIRTypeErrorException(final Class<?> typer, final QIRNode unknown) { + /** + * An expression that cannot be typed. + * + * @param typer The instance of {@link QIRTypeSystem} throwing the exception. + * @param unknown The expression that cannot be typed. + */ + public QIRTypeErrorException(final Class<? extends QIRTypeSystem> typer, final QIRNode unknown) { super(typer.getName() + " could not type unknown expression " + unknown); } - public QIRTypeErrorException(final Class<?> typer, final QIRVariable freeVariable) { + /** + * A free variable that cannot be typed. + * + * @param typer The instance of {@link QIRTypeSystem} throwing the exception. + * @param unknown The free variable that cannot be typed. + */ + public QIRTypeErrorException(final Class<? extends QIRTypeSystem> typer, final QIRVariable freeVariable) { super(typer.getName() + " could not type free variable " + freeVariable); } - public QIRTypeErrorException(final Class<?> typer, final QIRRecordType recordType, final String unknownColName) { - super(typer.getName() + " could not type column name " + unknownColName + " in record type " + recordType); + /** + * A record field that cannot be typed. + * + * @param typer The instance of {@link QIRTypeSystem} throwing the exception. + * @param unknown The record field that cannot be typed. + */ + public QIRTypeErrorException(final Class<? extends QIRTypeSystem> typer, final QIRRecordType recordType, final String unknownField) { + super(typer.getName() + " could not type field " + unknownField + " in record type " + recordType); } } diff --git a/src/qir/typing/QIRTypeSystem.java b/src/qir/typing/QIRTypeSystem.java new file mode 100644 index 0000000000000000000000000000000000000000..2679e6ae412e1630b051859f041dd485e3586710 --- /dev/null +++ b/src/qir/typing/QIRTypeSystem.java @@ -0,0 +1,10 @@ +package qir.typing; + +import qir.driver.IQIRVisitor; +import qir.types.QIRType; + +/** + * {@link QIRTypeSystem} represents any type system on a QIR expression. + */ +public abstract class QIRTypeSystem implements IQIRVisitor<QIRType> { +} diff --git a/src/qir/typing/QIRTypeSystemVisitor.java b/src/qir/typing/QIRTypeSystemVisitor.java deleted file mode 100644 index 9602577f983822cbf23baced9d07e206bf4bac20..0000000000000000000000000000000000000000 --- a/src/qir/typing/QIRTypeSystemVisitor.java +++ /dev/null @@ -1,7 +0,0 @@ -package qir.typing; - -import qir.driver.IQIRVisitor; -import qir.types.QIRType; - -public abstract class QIRTypeSystemVisitor implements IQIRVisitor<QIRType> { -}