
org.opalj.ai.Computation.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of abstract-interpretation-framework_2.13 Show documentation
Show all versions of abstract-interpretation-framework_2.13 Show documentation
Abstract Interpretation Framework
The newest version!
/* BSD 2-Clause License - see OPAL/LICENSE for details. */
package org.opalj
package ai
/**
* Encapsulates the result of a computation in a domain. In general, the
* result is either some value `V` or some exception(s) `E`. In some cases, however,
* when the domain cannot ''precisely'' determine the result, it may be both: some
* exceptional value(s) and a value.
*
* In the latter case the abstract interpreter will generally follow all
* possible paths. A computation that declares to return a result
* (i.e., the type `V` is not `Nothing`) must not return a result and/or throw an
* exception if the computation did not finish.
*
* ==Querying Computations==
* Before accessing a computation's result ([[result]] or [[exceptions]]) it first
* has to be checked whether the computation returned normally ([[returnsNormally]])
* or threw an exception ([[throwsException]]). Only if `returnsNormally` returns
* `true` the methods `result` and `hasResult` are defined.
*
* @tparam V The result of the computation. Typically a `DomainValue`;
* if the computation is executed for its side
* effect (e.g., as in case of a `monitorenter` or `monitorexit` instruction)
* the type of `V` maybe `Nothing`.
* @tparam E The exception(s) that maybe thrown by the computation. Typically,
* a `DomainValue` which represents a reference value with type
* `java.lang.Throwable` or a subtype thereof. If multiple exceptions may be
* thrown it may also be a set or `Iterable` of `DomainValue`s (e.g.,
* `ExceptionValues`).
*
* @note The precise requirements on the result of a computation are determined
* by the [[Domain]] object's methods that perform computations.
*
* @author Michael Eichberg
*/
sealed abstract class Computation[+V, +E] {
/**
* Returns `true` if this computation ''may have returned normally'' without
* throwing an exception. Given that some computations are performed for their
* side effect only, the computation may not have a result.
*/
def returnsNormally: Boolean
/**
* Returns `true` if this computation has a result value, `false` otherwise.
*
* @note A method with return type `void` may return normally ([[returnsNormally]]),
* but will never have a result. I.e., for such method, `hasResult` will always
* be false.
*/
def hasResult: Boolean
/**
* The return value of the computation (if any); defined if and only if
* `hasResult` returns true.
*/
@throws[UnsupportedOperationException]
def result: V
/**
* Returns `true` if this computation ''may have raised an exception''.
*/
def throwsException: Boolean
/**
* The exception or exceptions when the computation raised an exception;
* defined if and only if `throwsException` returns `true`.
*
* E.g., the invocation of a method may lead to several (checked/unchecked) exceptions.
*/
@throws[UnsupportedOperationException]
def exceptions: E
/**
* Updates the result associated with the represented computation.
*
* This method is only supported if the computation had a result!
*/
@throws[UnsupportedOperationException]
def updateResult[X](result: X): Computation[X, E]
/**
* Updates the exception associated with the represented computation.
*
* This method is only supported if the computation had an associated exception!
*/
@throws[UnsupportedOperationException]
def updateExceptions[X](exceptions: X): Computation[V, X]
}
/**
* Encapsulates the result of a computation that returned normally and
* that did not throw an exception.
*/
final case class ComputedValue[+V](result: V) extends Computation[V, Nothing] {
def returnsNormally: Boolean = true
def hasResult: Boolean = true
def updateResult[X](r: X): ComputedValue[X] = ComputedValue(r)
def throwsException: Boolean = false
def exceptions: Nothing =
throw new UnsupportedOperationException(
"the computation succeeded without an exception"
)
def updateExceptions[X](es: X): ComputedValue[V] =
throw new UnsupportedOperationException(
"the computation succeeded without an exception"
)
}
/**
* Encapsulates the result of a computation that either returned normally
* or threw an exception.
*/
final case class ComputedValueOrException[+V, +E](
result: V,
exceptions: E
) extends Computation[V, E] {
def returnsNormally: Boolean = true
def hasResult: Boolean = true
def updateResult[X](result: X): ComputedValueOrException[X, E] =
ComputedValueOrException(result, exceptions)
def throwsException: Boolean = true
def updateExceptions[X](exceptions: X): ComputedValueOrException[V, X] =
ComputedValueOrException(result, exceptions)
}
/**
* Encapsulates the result of a computation that threw an exception.
*/
final case class ThrowsException[+E](exceptions: E) extends Computation[Nothing, E] {
def returnsNormally: Boolean = false
def hasResult: Boolean = false
def result: Nothing =
throw new UnsupportedOperationException(
"the computation resulted in an exception"
)
def updateResult[X](result: X): ThrowsException[E] =
throw new UnsupportedOperationException(
"the computation resulted in an exception"
)
def throwsException: Boolean = true
def updateExceptions[X](exceptions: X): ThrowsException[X] =
ThrowsException(exceptions)
}
/**
* Encapsulates the result of a computation that returned normally (but which
* did not return some value) or that threw an exception/multiple exceptions.
*/
final case class ComputationWithSideEffectOrException[+E](
exceptions: E
) extends Computation[Nothing, E] {
def returnsNormally: Boolean = true
def hasResult: Boolean = false
def updateResult[X](result: X): ComputationWithSideEffectOrException[E] =
throw new UnsupportedOperationException("the computation only had side effects")
def result: Nothing =
throw new UnsupportedOperationException(
"the computation was executed for its side effect only"
)
def throwsException: Boolean = true
def updateExceptions[X](es: X): ComputationWithSideEffectOrException[X] =
ComputationWithSideEffectOrException(es)
}
/**
* Represents a computation that completed normally.
*/
case object ComputationWithSideEffectOnly extends Computation[Nothing, Nothing] {
def returnsNormally: Boolean = true
def hasResult: Boolean = false
def result: Nothing =
throw new UnsupportedOperationException(
"the computation was executed for its side effect only"
)
def updateResult[X](result: X): ComputationWithSideEffectOnly.type =
throw new UnsupportedOperationException("the computation only had side effects")
def throwsException: Boolean = false
def exceptions: Nothing =
throw new UnsupportedOperationException(
"the computation succeeded without an exception"
)
def updateExceptions[X](es: X): ComputationWithSideEffectOnly.type =
throw new UnsupportedOperationException(
"the computation succeeded without an exception"
)
}
/**
* Indicates that the computation did not succeed. This is typically the case
* for methods that contain an endless loop, such as:
* {{{
* while(true){.../* no break statements */}
* }}}
*/
case object ComputationFailed extends Computation[Nothing, Nothing] {
def returnsNormally: Boolean = false
def hasResult: Boolean = false
def result: Nothing = throw new UnsupportedOperationException("the computation failed")
def updateResult[X](result: X): ComputationFailed.type = {
throw new UnsupportedOperationException("the computation failed")
}
def throwsException: Boolean = false
def exceptions: Nothing = throw new UnsupportedOperationException("the computation failed")
def updateExceptions[X](es: X): ComputationFailed.type = {
throw new UnsupportedOperationException("the computation failed")
}
}
// -------------------------------------------------------------------------------------------------
//
// EXTRACTORS
//
// -------------------------------------------------------------------------------------------------
object ComputationWithResultAndException {
def unapply[V, E](c: Computation[V, E]): Option[(V, E)] = {
if (c.hasResult && c.throwsException) Some((c.result, c.exceptions)) else None
}
}
object ComputationWithResult {
def unapply[V](c: Computation[V, _]): Option[V] = {
if (c.hasResult) Some(c.result) else None
}
}
object ComputationWithException {
def unapply[E](c: Computation[_, E]): Option[E] = {
if (c.throwsException) Some(c.exceptions) else None
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy