diff --git a/examples/src/kotlin/org/partiql/examples/ParserErrorExample.kt b/examples/src/kotlin/org/partiql/examples/ParserErrorExample.kt index abe85375e..a32ff520a 100644 --- a/examples/src/kotlin/org/partiql/examples/ParserErrorExample.kt +++ b/examples/src/kotlin/org/partiql/examples/ParserErrorExample.kt @@ -28,7 +28,7 @@ class ParserErrorExample(out: PrintStream) : Example(out) { throw Exception("ParserException was not thrown") } catch (e: ParserException) { - val errorContext = e.errorContext!! + val errorContext = e.errorContext val errorInformation = "errorCode: ${e.errorCode}" + "\nLINE_NUMBER: ${errorContext[Property.LINE_NUMBER]}" + diff --git a/lang/src/org/partiql/lang/CompilerPipeline.kt b/lang/src/org/partiql/lang/CompilerPipeline.kt index 31751e48a..57ec44f2a 100644 --- a/lang/src/org/partiql/lang/CompilerPipeline.kt +++ b/lang/src/org/partiql/lang/CompilerPipeline.kt @@ -205,7 +205,7 @@ interface CompilerPipeline { fun build(): CompilerPipeline { val compileOptionsToUse = compileOptions ?: CompileOptions.standard() - when (compileOptionsToUse.thunkReturnTypeAssertions) { + when (compileOptionsToUse.thunkOptions.thunkReturnTypeAssertions) { ThunkReturnTypeAssertions.DISABLED -> { /* intentionally blank */ } ThunkReturnTypeAssertions.ENABLED -> { check(this.globalTypeBindings != null) { diff --git a/lang/src/org/partiql/lang/SqlException.kt b/lang/src/org/partiql/lang/SqlException.kt index fd64cc923..2b8100b51 100644 --- a/lang/src/org/partiql/lang/SqlException.kt +++ b/lang/src/org/partiql/lang/SqlException.kt @@ -18,6 +18,7 @@ import org.partiql.lang.errors.ErrorCode import org.partiql.lang.errors.Property import org.partiql.lang.errors.PropertyValueMap import org.partiql.lang.errors.UNKNOWN +import org.partiql.lang.util.propertyValueMapOf /** * General exception class for the interpreter. @@ -33,7 +34,7 @@ import org.partiql.lang.errors.UNKNOWN * * @param message the message for this exception * @param errorCode the error code for this exception - * @param propertyValueMap context for this error + * @param errorContextArg context for this error, contains details like line & column number among other attributes. * @param cause for this exception * * @constructor a custom error [message], the [errorCode], error context as a [propertyValueMap] and optional [cause] creates an @@ -43,10 +44,11 @@ import org.partiql.lang.errors.UNKNOWN open class SqlException( override var message: String, val errorCode: ErrorCode, - val errorContext: PropertyValueMap? = null, + errorContextArg: PropertyValueMap? = null, cause: Throwable? = null -) : - RuntimeException(message, cause) { +) : RuntimeException(message, cause) { + + val errorContext: PropertyValueMap = errorContextArg ?: propertyValueMapOf() /** * Indicates if this exception is due to an internal error or not. diff --git a/lang/src/org/partiql/lang/eval/CompileOptions.kt b/lang/src/org/partiql/lang/eval/CompileOptions.kt index a26511e01..412507743 100644 --- a/lang/src/org/partiql/lang/eval/CompileOptions.kt +++ b/lang/src/org/partiql/lang/eval/CompileOptions.kt @@ -141,6 +141,7 @@ enum class ThunkReturnTypeAssertions { * @param defaultTimezoneOffset Default timezone offset to be used when TIME WITH TIME ZONE does not explicitly * specify the time zone. Defaults to [ZoneOffset.UTC] */ +@Suppress("DataClassPrivateConstructor") data class CompileOptions private constructor ( val undefinedVariable: UndefinedVariableBehavior, val projectionIteration: ProjectionIterationBehavior = ProjectionIterationBehavior.FILTER_MISSING, @@ -148,7 +149,6 @@ data class CompileOptions private constructor ( val thunkOptions: ThunkOptions = ThunkOptions.standard(), val typingMode: TypingMode = TypingMode.LEGACY, val typedOpBehavior: TypedOpBehavior = TypedOpBehavior.LEGACY, - val thunkReturnTypeAssertions: ThunkReturnTypeAssertions = ThunkReturnTypeAssertions.DISABLED, val defaultTimezoneOffset: ZoneOffset = ZoneOffset.UTC ) { @@ -177,7 +177,7 @@ data class CompileOptions private constructor ( fun build(options: CompileOptions, block: Builder.() -> Unit) = Builder(options).apply(block).build() /** - * Creates a [CompileOptions] instance with the standard values. + * Creates a [CompileOptions] instance with the standard values for use by the legacy AST compiler. */ @JvmStatic fun standard() = Builder().build() @@ -194,7 +194,7 @@ data class CompileOptions private constructor ( fun typingMode(value: TypingMode) = set { copy(typingMode = value) } fun typedOpBehavior(value: TypedOpBehavior) = set { copy(typedOpBehavior = value) } fun thunkOptions(value: ThunkOptions) = set { copy(thunkOptions = value) } - fun evaluationTimeTypeChecks(value: ThunkReturnTypeAssertions) = set { copy(thunkReturnTypeAssertions = value) } + fun thunkOptions(build: ThunkOptions.Builder.() -> Unit) = set { copy(thunkOptions = ThunkOptions.build(build)) } fun defaultTimezoneOffset(value: ZoneOffset) = set { copy(defaultTimezoneOffset = value) } private inline fun set(block: CompileOptions.() -> CompileOptions): Builder { diff --git a/lang/src/org/partiql/lang/eval/EvaluatingCompiler.kt b/lang/src/org/partiql/lang/eval/EvaluatingCompiler.kt index 3da7286d0..646f60258 100644 --- a/lang/src/org/partiql/lang/eval/EvaluatingCompiler.kt +++ b/lang/src/org/partiql/lang/eval/EvaluatingCompiler.kt @@ -87,6 +87,25 @@ import java.util.TreeSet import java.util.regex.Pattern import kotlin.Comparator +/** + * A thunk with no parameters other than the current environment. + * + * See https://en.wikipedia.org/wiki/Thunk + * + * This name was chosen because it is a thunk that accepts an instance of `Environment`. + */ +private typealias ThunkEnv = Thunk + +/** + * A thunk taking a single [T] argument and the current environment. + * + * See https://en.wikipedia.org/wiki/Thunk + * + * This name was chosen because it is a thunk that accepts an instance of `Environment` and an [ExprValue] as + * its arguments. + */ +private typealias ThunkEnvValue = ThunkValue + /** * A basic compiler that converts an instance of [PartiqlAst] to an [Expression]. * @@ -116,7 +135,7 @@ internal class EvaluatingCompiler( private val compileOptions: CompileOptions = CompileOptions.standard() ) { private val errorSignaler = compileOptions.typingMode.createErrorSignaler(valueFactory) - private val thunkFactory = compileOptions.typingMode.createThunkFactory(compileOptions, valueFactory) + private val thunkFactory = compileOptions.typingMode.createThunkFactory(compileOptions.thunkOptions, valueFactory) private val compilationContextStack = Stack() diff --git a/lang/src/org/partiql/lang/eval/Exceptions.kt b/lang/src/org/partiql/lang/eval/Exceptions.kt index e00c8490a..49a574a5b 100644 --- a/lang/src/org/partiql/lang/eval/Exceptions.kt +++ b/lang/src/org/partiql/lang/eval/Exceptions.kt @@ -125,6 +125,10 @@ fun fillErrorContext(errorContext: PropertyValueMap, metaContainer: MetaContaine } } +/** + * Returns the [SourceLocationMeta] as an error context if the [SourceLocationMeta.TAG] exists in the passed + * [metaContainer]. Otherwise, returns an empty map. + */ fun errorContextFrom(metaContainer: MetaContainer?): PropertyValueMap { if (metaContainer == null) { return PropertyValueMap() diff --git a/lang/src/org/partiql/lang/eval/Thunk.kt b/lang/src/org/partiql/lang/eval/Thunk.kt index 8ef756639..60b715c18 100644 --- a/lang/src/org/partiql/lang/eval/Thunk.kt +++ b/lang/src/org/partiql/lang/eval/Thunk.kt @@ -27,19 +27,21 @@ import org.partiql.lang.errors.Property * * See https://en.wikipedia.org/wiki/Thunk * - * This name was chosen because it is a thunk that accepts an instance of `Environment`. + * @param TEnv The type of the environment. Generic so that the legacy AST compiler and the new compiler may use + * different types here. */ -internal typealias ThunkEnv = (Environment) -> ExprValue +internal typealias Thunk = (TEnv) -> ExprValue /** - * A thunk taking a single [T] argument and the current environment. + * A thunk taking a single argument and the current environment. * * See https://en.wikipedia.org/wiki/Thunk * - * This name was chosen because it is a thunk that accepts an instance of `Environment` and an [ExprValue] as - * its arguments. + * @param TEnv The type of the environment. Generic so that the legacy AST compiler and the new compiler may use + * different types here. + * @param TArg The type of the additional argument. */ -internal typealias ThunkEnvValue = (Environment, T) -> ExprValue +internal typealias ThunkValue = (TEnv, TArg) -> ExprValue /** * A type alias for an exception handler which always throws(primarily used for [TypingMode.LEGACY]). @@ -56,12 +58,17 @@ internal typealias ThunkExceptionHandlerForPermissiveMode = (Throwable, SourceLo * * - [handleExceptionForLegacyMode] will be called when in [TypingMode.LEGACY] mode * - [handleExceptionForPermissiveMode] will be called when in [TypingMode.PERMISSIVE] mode + * - [thunkReturnTypeAssertions] is intended for testing only, and ensures that the return value of every expression + * conforms to its `StaticType` meta. This has negative performance implications so should be avoided in production + * environments. This only be used for testing and diagnostic purposes only. * The default exception handler wraps any [Throwable] exception and throws [EvaluationException] */ data class ThunkOptions private constructor( val handleExceptionForLegacyMode: ThunkExceptionHandlerForLegacyMode = DEFAULT_EXCEPTION_HANDLER_FOR_LEGACY_MODE, - val handleExceptionForPermissiveMode: ThunkExceptionHandlerForPermissiveMode = DEFAULT_EXCEPTION_HANDLER_FOR_PERMISSIVE_MODE + val handleExceptionForPermissiveMode: ThunkExceptionHandlerForPermissiveMode = DEFAULT_EXCEPTION_HANDLER_FOR_PERMISSIVE_MODE, + val thunkReturnTypeAssertions: ThunkReturnTypeAssertions = ThunkReturnTypeAssertions.DISABLED, ) { + companion object { /** @@ -89,6 +96,7 @@ data class ThunkOptions private constructor( private var options = ThunkOptions() fun handleExceptionForLegacyMode(value: ThunkExceptionHandlerForLegacyMode) = set { copy(handleExceptionForLegacyMode = value) } fun handleExceptionForPermissiveMode(value: ThunkExceptionHandlerForPermissiveMode) = set { copy(handleExceptionForPermissiveMode = value) } + fun evaluationTimeTypeChecks(value: ThunkReturnTypeAssertions) = set { copy(thunkReturnTypeAssertions = value) } private inline fun set(block: ThunkOptions.() -> ThunkOptions): Builder { options = block(options) return this @@ -116,18 +124,18 @@ internal val DEFAULT_EXCEPTION_HANDLER_FOR_PERMISSIVE_MODE: ThunkExceptionHandle * - when [TypingMode] is [TypingMode.LEGACY], creates [LegacyThunkFactory] * - when [TypingMode] is [TypingMode.PERMISSIVE], creates [PermissiveThunkFactory] */ -internal fun TypingMode.createThunkFactory( - compileOptions: CompileOptions, +internal fun TypingMode.createThunkFactory( + thunkOptions: ThunkOptions, valueFactory: ExprValueFactory -): ThunkFactory = when (this) { - TypingMode.LEGACY -> LegacyThunkFactory(compileOptions, valueFactory) - TypingMode.PERMISSIVE -> PermissiveThunkFactory(compileOptions, valueFactory) +): ThunkFactory = when (this) { + TypingMode.LEGACY -> LegacyThunkFactory(thunkOptions, valueFactory) + TypingMode.PERMISSIVE -> PermissiveThunkFactory(thunkOptions, valueFactory) } /** * Provides methods for constructing new thunks according to the specified [CompileOptions]. */ -internal abstract class ThunkFactory( - val compileOptions: CompileOptions, +internal abstract class ThunkFactory( + val thunkOptions: ThunkOptions, val valueFactory: ExprValueFactory ) { private fun checkEvaluationTimeType(thunkResult: ExprValue, metas: MetaContainer): ExprValue { @@ -157,11 +165,11 @@ internal abstract class ThunkFactory( * confusion in the case [StaticTypeInferenceVisitorTransform] has a bug which prevents it from assigning a * [StaticTypeMeta] or in case it is not run at all. */ - protected fun ThunkEnv.typeCheck(metas: MetaContainer): ThunkEnv = - when (compileOptions.thunkReturnTypeAssertions) { + protected fun Thunk.typeCheck(metas: MetaContainer): Thunk = + when (thunkOptions.thunkReturnTypeAssertions) { ThunkReturnTypeAssertions.DISABLED -> this ThunkReturnTypeAssertions.ENABLED -> { - val wrapper = { env: Environment -> + val wrapper = { env: TEnv -> val thunkResult: ExprValue = this(env) checkEvaluationTimeType(thunkResult, metas) } @@ -169,12 +177,12 @@ internal abstract class ThunkFactory( } } - /** Same as [typeCheck] but works on a [ThunkEnvValue] instead of a [ThunkEnv]. */ - protected fun ThunkEnvValue.typeCheckEnvValue(metas: MetaContainer): ThunkEnvValue = - when (compileOptions.thunkReturnTypeAssertions) { + /** Same as [typeCheck] but works on a [ThunkEnvValue] instead of a [Thunk]. */ + protected fun ThunkValue.typeCheckEnvValue(metas: MetaContainer): ThunkValue = + when (thunkOptions.thunkReturnTypeAssertions) { ThunkReturnTypeAssertions.DISABLED -> this ThunkReturnTypeAssertions.ENABLED -> { - val wrapper = { env: Environment, value: ExprValue -> + val wrapper = { env: TEnv, value: ExprValue -> val thunkResult: ExprValue = this(env, value) checkEvaluationTimeType(thunkResult, metas) } @@ -182,12 +190,12 @@ internal abstract class ThunkFactory( } } - /** Same as [typeCheck] but works on a [ThunkEnvValue>] instead of a [ThunkEnv]. */ - protected fun ThunkEnvValue>.typeCheckEnvValueList(metas: MetaContainer): ThunkEnvValue> = - when (compileOptions.thunkReturnTypeAssertions) { + /** Same as [typeCheck] but works on a [ThunkEnvValue>] instead of a [Thunk]. */ + protected fun ThunkValue>.typeCheckEnvValueList(metas: MetaContainer): ThunkValue> = + when (thunkOptions.thunkReturnTypeAssertions) { ThunkReturnTypeAssertions.DISABLED -> this ThunkReturnTypeAssertions.ENABLED -> { - val wrapper = { env: Environment, value: List -> + val wrapper = { env: TEnv, value: List -> val thunkResult: ExprValue = this(env, value) checkEvaluationTimeType(thunkResult, metas) } @@ -196,17 +204,17 @@ internal abstract class ThunkFactory( } /** - * Creates a [ThunkEnv] which handles exceptions by wrapping them into an [EvaluationException] which uses + * Creates a [Thunk] which handles exceptions by wrapping them into an [EvaluationException] which uses * [handleException] to handle exceptions appropriately. * * Literal lambdas passed to this function as [t] are inlined into the body of the function being returned, which * reduces the need to create additional call contexts. The lambdas passed as [t] may not contain non-local returns * (`crossinline`). */ - internal inline fun thunkEnv(metas: MetaContainer, crossinline t: ThunkEnv): ThunkEnv { + internal inline fun thunkEnv(metas: MetaContainer, crossinline t: Thunk): Thunk { val sourceLocationMeta = metas[SourceLocationMeta.TAG] as? SourceLocationMeta - return { env: Environment -> + return { env: TEnv -> handleException(sourceLocationMeta) { t(env) } @@ -221,8 +229,11 @@ internal abstract class ThunkFactory( * * For all [TypingMode]s, if the values returned by [getVal1], [getVal2] and [getVal2] are all known, * [compute] is invoked to perform the operation-specific computation. + * + * Note: this must be public due to a Kotlin compiler bug: https://youtrack.jetbrains.com/issue/KT-22625. + * This shouldn't matter though because this class is still `internal`. */ - protected abstract fun propagateUnknowns( + abstract fun propagateUnknowns( getVal1: () -> ExprValue, getVal2: (() -> ExprValue)?, getVal3: (() -> ExprValue)?, @@ -232,14 +243,17 @@ internal abstract class ThunkFactory( /** * Similar to the other [propagateUnknowns] overload, performs unknown propagation for a variadic sequence of * operations. + * + * Note: this must be public due to a Kotlin compiler bug: https://youtrack.jetbrains.com/issue/KT-22625. + * This shouldn't matter though because this class is still `internal`. */ - protected abstract fun propagateUnknowns( + abstract fun propagateUnknowns( operands: Sequence, compute: (List) -> ExprValue ): ExprValue /** - * Creates a thunk that accepts three [ThunkEnv] operands ([t1], [t2], and [t3]), evaluates them and propagates + * Creates a thunk that accepts three [Thunk] operands ([t1], [t2], and [t3]), evaluates them and propagates * unknowns according to the current [TypingMode]. When possible, use this function or one of its overloads * instead of [thunkEnv] when the operation requires propagation of unknown values. * @@ -260,48 +274,48 @@ internal abstract class ThunkFactory( */ internal inline fun thunkEnvOperands( metas: MetaContainer, - crossinline t1: ThunkEnv, - crossinline t2: ThunkEnv, - crossinline t3: ThunkEnv, - crossinline compute: (Environment, ExprValue, ExprValue, ExprValue) -> ExprValue - ): ThunkEnv = + crossinline t1: Thunk, + crossinline t2: Thunk, + crossinline t3: Thunk, + crossinline compute: (TEnv, ExprValue, ExprValue, ExprValue) -> ExprValue + ): Thunk = thunkEnv(metas) { env -> propagateUnknowns({ t1(env) }, { t2(env) }, { t3(env) }) { v1, v2, v3 -> compute(env, v1, v2!!, v3!!) } }.typeCheck(metas) - /** See the [thunkEnvOperands] with three [ThunkEnv] operands. */ + /** See the [thunkEnvOperands] with three [Thunk] operands. */ internal inline fun thunkEnvOperands( metas: MetaContainer, - crossinline t1: ThunkEnv, - crossinline t2: ThunkEnv, - crossinline compute: (Environment, ExprValue, ExprValue) -> ExprValue - ): ThunkEnv = + crossinline t1: Thunk, + crossinline t2: Thunk, + crossinline compute: (TEnv, ExprValue, ExprValue) -> ExprValue + ): Thunk = this.thunkEnv(metas) { env -> propagateUnknowns({ t1(env) }, { t2(env) }, null) { v1, v2, _ -> compute(env, v1, v2!!) } }.typeCheck(metas) - /** See the [thunkEnvOperands] with three [ThunkEnv] operands. */ + /** See the [thunkEnvOperands] with three [Thunk] operands. */ internal inline fun thunkEnvOperands( metas: MetaContainer, - crossinline t1: ThunkEnv, - crossinline compute: (Environment, ExprValue) -> ExprValue - ): ThunkEnv = + crossinline t1: Thunk, + crossinline compute: (TEnv, ExprValue) -> ExprValue + ): Thunk = this.thunkEnv(metas) { env -> propagateUnknowns({ t1(env) }, null, null) { v1, _, _ -> compute(env, v1) } }.typeCheck(metas) - /** See the [thunkEnvOperands] with a variadic list of [ThunkEnv] operands. */ + /** See the [thunkEnvOperands] with a variadic list of [Thunk] operands. */ internal inline fun thunkEnvOperands( metas: MetaContainer, - operandThunks: List, - crossinline compute: (Environment, List) -> ExprValue - ): ThunkEnv { + operandThunks: List>, + crossinline compute: (TEnv, List) -> ExprValue + ): Thunk { return this.thunkEnv(metas) { env -> val operandSeq = sequence { operandThunks.forEach { yield(it(env)) } } @@ -314,11 +328,11 @@ internal abstract class ThunkFactory( /** Similar to [thunkEnv], but creates a [ThunkEnvValue] instead. */ internal inline fun thunkEnvValue( metas: MetaContainer, - crossinline t: ThunkEnvValue - ): ThunkEnvValue { + crossinline t: ThunkValue + ): ThunkValue { val sourceLocationMeta = metas[SourceLocationMeta.TAG] as? SourceLocationMeta - return { env: Environment, arg1: ExprValue -> + return { env: TEnv, arg1: ExprValue -> handleException(sourceLocationMeta) { t(env, arg1) } @@ -328,11 +342,11 @@ internal abstract class ThunkFactory( /** Similar to [thunkEnv], but creates a [ThunkEnvValue>] instead. */ internal inline fun thunkEnvValueList( metas: MetaContainer, - crossinline t: ThunkEnvValue> - ): ThunkEnvValue> { + crossinline t: ThunkValue> + ): ThunkValue> { val sourceLocationMeta = metas[SourceLocationMeta.TAG] as? SourceLocationMeta - return { env: Environment, arg1: List -> + return { env: TEnv, arg1: List -> handleException(sourceLocationMeta) { t(env, arg1) } @@ -353,9 +367,9 @@ internal abstract class ThunkFactory( */ internal abstract fun thunkFold( metas: MetaContainer, - argThunks: List, + argThunks: List>, op: (ExprValue, ExprValue) -> ExprValue - ): ThunkEnv + ): Thunk /** * Similar to [thunkFold] but intended for comparison operators, i.e. `=`, `>`, `>=`, `<`, `<=`. @@ -374,35 +388,25 @@ internal abstract class ThunkFactory( */ internal abstract fun thunkAndMap( metas: MetaContainer, - argThunks: List, + argThunks: List>, op: (ExprValue, ExprValue) -> Boolean - ): ThunkEnv + ): Thunk /** Populates [exception] with the line & column from the specified [SourceLocationMeta]. */ protected fun populateErrorContext( exception: EvaluationException, sourceLocation: SourceLocationMeta? - ) = when (exception.errorContext) { - null -> - EvaluationException( - message = exception.message, - errorCode = exception.errorCode, - errorContext = errorContextFrom(sourceLocation), - cause = exception, - internal = exception.internal - ) - else -> { - // Only add source location data to the error context if it doesn't already exist - // in [errorContext]. - if (!exception.errorContext.hasProperty(Property.LINE_NUMBER)) { - sourceLocation?.let { fillErrorContext(exception.errorContext, sourceLocation) } - } - exception + ): EvaluationException { + // Only add source location data to the error context if it doesn't already exist + // in [errorContext]. + if (!exception.errorContext.hasProperty(Property.LINE_NUMBER)) { + sourceLocation?.let { fillErrorContext(exception.errorContext, sourceLocation) } } + return exception } /** - * Handles exceptions appropriately for a run-time [ThunkEnv]. + * Handles exceptions appropriately for a run-time [Thunk]. * * - The [SourceLocationMeta] will be extracted from [MetaContainer] and included in any [EvaluationException] that * is thrown, if present. @@ -419,10 +423,10 @@ internal abstract class ThunkFactory( /** * Provides methods for constructing new thunks according to the specified [CompileOptions] for [TypingMode.LEGACY] behaviour. */ -internal class LegacyThunkFactory( - compileOptions: CompileOptions, +internal class LegacyThunkFactory( + thunkOptions: ThunkOptions, valueFactory: ExprValueFactory -) : ThunkFactory(compileOptions, valueFactory) { +) : ThunkFactory(thunkOptions, valueFactory) { override fun propagateUnknowns( getVal1: () -> ExprValue, @@ -470,9 +474,9 @@ internal class LegacyThunkFactory( /** See [ThunkFactory.thunkFold]. */ override fun thunkFold( metas: MetaContainer, - argThunks: List, + argThunks: List>, op: (ExprValue, ExprValue) -> ExprValue - ): ThunkEnv { + ): Thunk { require(argThunks.isNotEmpty()) { "argThunks must not be empty" } val firstThunk = argThunks.first() @@ -498,9 +502,9 @@ internal class LegacyThunkFactory( /** See [ThunkFactory.thunkAndMap]. */ override fun thunkAndMap( metas: MetaContainer, - argThunks: List, + argThunks: List>, op: (ExprValue, ExprValue) -> Boolean - ): ThunkEnv { + ): Thunk { require(argThunks.size >= 2) { "argThunks must have at least two elements" } val firstThunk = argThunks.first() @@ -534,7 +538,7 @@ internal class LegacyThunkFactory( } /** - * Handles exceptions appropriately for a run-time [ThunkEnv] respecting [TypingMode.LEGACY] behaviour. + * Handles exceptions appropriately for a run-time [Thunk] respecting [TypingMode.LEGACY] behaviour. * * - The [SourceLocationMeta] will be extracted from [MetaContainer] and included in any [EvaluationException] that * is thrown, if present. @@ -551,7 +555,7 @@ internal class LegacyThunkFactory( } catch (e: EvaluationException) { throw populateErrorContext(e, sourceLocation) } catch (e: Exception) { - compileOptions.thunkOptions.handleExceptionForLegacyMode(e, sourceLocation) + thunkOptions.handleExceptionForLegacyMode(e, sourceLocation) } } @@ -559,10 +563,10 @@ internal class LegacyThunkFactory( * Provides methods for constructing new thunks according to the specified [CompileOptions] and for * [TypingMode.PERMISSIVE] behaviour. */ -internal class PermissiveThunkFactory( - compileOptions: CompileOptions, +internal class PermissiveThunkFactory( + thunkOptions: ThunkOptions, valueFactory: ExprValueFactory -) : ThunkFactory(compileOptions, valueFactory) { +) : ThunkFactory(thunkOptions, valueFactory) { override fun propagateUnknowns( getVal1: () -> ExprValue, @@ -628,9 +632,9 @@ internal class PermissiveThunkFactory( /** See [ThunkFactory.thunkFold]. */ override fun thunkFold( metas: MetaContainer, - argThunks: List, + argThunks: List>, op: (ExprValue, ExprValue) -> ExprValue - ): ThunkEnv { + ): Thunk { require(argThunks.isNotEmpty()) { "argThunks must not be empty" } return thunkEnv(metas) { env -> @@ -654,9 +658,9 @@ internal class PermissiveThunkFactory( /** See [ThunkFactory.thunkAndMap]. */ override fun thunkAndMap( metas: MetaContainer, - argThunks: List, + argThunks: List>, op: (ExprValue, ExprValue) -> Boolean - ): ThunkEnv { + ): Thunk { require(argThunks.size >= 2) { "argThunks must have at least two elements" } return thunkEnv(metas) thunkBlock@{ env -> @@ -684,7 +688,7 @@ internal class PermissiveThunkFactory( } /** - * Handles exceptions appropriately for a run-time [ThunkEnv] respecting [TypingMode.PERMISSIVE] behaviour. + * Handles exceptions appropriately for a run-time [Thunk] respecting [TypingMode.PERMISSIVE] behaviour. * * - Exceptions thrown by [block] that are [EvaluationException] are caught and [MissingExprValue] is returned. * - Exceptions thrown by [block] that are not an [EvaluationException] cause an [EvaluationException] to be thrown @@ -697,13 +701,13 @@ internal class PermissiveThunkFactory( try { block() } catch (e: EvaluationException) { - compileOptions.thunkOptions.handleExceptionForPermissiveMode(e, sourceLocation) + thunkOptions.handleExceptionForPermissiveMode(e, sourceLocation) when (e.errorCode.errorBehaviorInPermissiveMode) { // Rethrows the exception as it does in LEGACY mode. ErrorBehaviorInPermissiveMode.THROW_EXCEPTION -> throw populateErrorContext(e, sourceLocation) ErrorBehaviorInPermissiveMode.RETURN_MISSING -> valueFactory.missingValue } } catch (e: Exception) { - compileOptions.thunkOptions.handleExceptionForLegacyMode(e, sourceLocation) + thunkOptions.handleExceptionForLegacyMode(e, sourceLocation) } } diff --git a/lang/test/org/partiql/lang/eval/ErrorSignalerTests.kt b/lang/test/org/partiql/lang/eval/ErrorSignalerTests.kt index f3de26e96..3c509ddb9 100644 --- a/lang/test/org/partiql/lang/eval/ErrorSignalerTests.kt +++ b/lang/test/org/partiql/lang/eval/ErrorSignalerTests.kt @@ -37,8 +37,8 @@ class ErrorSignalerTests { ex } assertEquals(ex.errorCode, ErrorCode.EVALUATOR_CAST_FAILED) - assertEquals(ex.errorContext!![Property.LINE_NUMBER]!!.longValue(), 4L) - assertEquals(ex.errorContext!![Property.COLUMN_NUMBER]!!.longValue(), 2L) + assertEquals(ex.errorContext[Property.LINE_NUMBER]!!.longValue(), 4L) + assertEquals(ex.errorContext[Property.COLUMN_NUMBER]!!.longValue(), 2L) } private fun runTest(ctx1: ErrorSignaler, value: Int): ExprValue = diff --git a/lang/test/org/partiql/lang/eval/EvaluatorStaticTypeTests.kt b/lang/test/org/partiql/lang/eval/EvaluatorStaticTypeTests.kt index ba3fc2420..d0cd75836 100644 --- a/lang/test/org/partiql/lang/eval/EvaluatorStaticTypeTests.kt +++ b/lang/test/org/partiql/lang/eval/EvaluatorStaticTypeTests.kt @@ -187,8 +187,10 @@ class EvaluatorStaticTypeTests { // set permissive mode typingMode(TypingMode.PERMISSIVE) - // enable evaluation time type checking - evaluationTimeTypeChecks(ThunkReturnTypeAssertions.ENABLED) + thunkOptions { + // enable evaluation time type checking + evaluationTimeTypeChecks(ThunkReturnTypeAssertions.ENABLED) + } } ) } diff --git a/lang/test/org/partiql/lang/eval/ThunkFactoryTests.kt b/lang/test/org/partiql/lang/eval/ThunkFactoryTests.kt index c288dda71..3d12ea3b6 100644 --- a/lang/test/org/partiql/lang/eval/ThunkFactoryTests.kt +++ b/lang/test/org/partiql/lang/eval/ThunkFactoryTests.kt @@ -20,8 +20,8 @@ import kotlin.test.assertEquals class ThunkFactoryTests { companion object { - private val compileOptions = CompileOptions.build { - this.evaluationTimeTypeChecks(ThunkReturnTypeAssertions.ENABLED) + private val compileOptions = ThunkOptions.build { + evaluationTimeTypeChecks(ThunkReturnTypeAssertions.ENABLED) } private val valueFactory = ExprValueFactory.standard(ION) @@ -38,7 +38,7 @@ class ThunkFactoryTests { val expectedType: StaticType, val thunkReturnValue: ExprValue, val expectError: Boolean, - internal val thunkFactory: ThunkFactory + internal val thunkFactory: ThunkFactory ) { val metas = metaContainerOf(StaticTypeMeta(expectedType)) val fakeThunk = thunkFactory.thunkEnv(IRRELEVANT_METAS) { IRRELEVANT } diff --git a/lang/test/org/partiql/lang/eval/TypingModeTests.kt b/lang/test/org/partiql/lang/eval/TypingModeTests.kt index 28adb263d..a771b54e5 100644 --- a/lang/test/org/partiql/lang/eval/TypingModeTests.kt +++ b/lang/test/org/partiql/lang/eval/TypingModeTests.kt @@ -64,12 +64,12 @@ class TypingModeTests : EvaluatorTestBase() { assertEquals( "line number", tc.expectedLegacyError.lineNum.toLong(), - ex.errorContext?.get(Property.LINE_NUMBER)?.longValue() + ex.errorContext[Property.LINE_NUMBER]?.longValue() ) assertEquals( "column number", tc.expectedLegacyError.charOffset.toLong(), - ex.errorContext?.get(Property.COLUMN_NUMBER)?.longValue() + ex.errorContext[Property.COLUMN_NUMBER]?.longValue() ) } ) diff --git a/lang/test/org/partiql/lang/eval/visitors/StaticTypeVisitorTransformTests.kt b/lang/test/org/partiql/lang/eval/visitors/StaticTypeVisitorTransformTests.kt index 7a214d4c6..0b7220b6c 100644 --- a/lang/test/org/partiql/lang/eval/visitors/StaticTypeVisitorTransformTests.kt +++ b/lang/test/org/partiql/lang/eval/visitors/StaticTypeVisitorTransformTests.kt @@ -845,7 +845,7 @@ class StaticTypeVisitorTransformTests : VisitorTransformTestBase() { properties.forEach { (property, expectedValue) -> assertEquals( "${property.propertyName} in error doesn't match", - expectedValue, it.error.errorContext?.get(property)?.value + expectedValue, it.error.errorContext[property]?.value ) } }