All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.it.unibo.tuprolog.solve.library.impl.RuntimeImpl.kt Maven / Gradle / Ivy

package it.unibo.tuprolog.solve.library.impl

import it.unibo.tuprolog.core.Clause
import it.unibo.tuprolog.core.operators.OperatorSet
import it.unibo.tuprolog.solve.Signature
import it.unibo.tuprolog.solve.function.LogicFunction
import it.unibo.tuprolog.solve.library.Library
import it.unibo.tuprolog.solve.library.Runtime
import it.unibo.tuprolog.solve.library.exception.AlreadyLoadedLibraryException
import it.unibo.tuprolog.solve.library.exception.NoSuchALibraryException
import it.unibo.tuprolog.solve.primitive.Primitive
import it.unibo.tuprolog.theory.Theory
import it.unibo.tuprolog.unify.Unificator
import it.unibo.tuprolog.utils.Cache

/** A class representing an agglomerate of libraries with an alias */
internal class RuntimeImpl(private val delegate: Map) :
    Runtime,
    AbstractPluggable(),
    Map by delegate {
    constructor(libraries: Sequence) : this(libraries.map { it.alias to it }.toMap())

    /** All aliases of all libraries included in this library group */
    override val aliases: Set
        get() = keys

    override val libraries: Set
        get() = values.toSet()

    private val theoryCache: Cache = Cache.simpleLru(1)

    override fun asTheory(unificator: Unificator): Theory =
        theoryCache.getOrSet(unificator) {
            Theory.indexedOf(unificator, clauses)
        }

    override val operators: OperatorSet by lazy {
        OperatorSet(libraries.flatMap { it.operators.asSequence() })
    }

    override val clauses: List
        get() = libraries.flatMap { it.clauses }

    override val primitives: Map by lazy {
        libraries.flatMap { lib ->
            lib.primitives.entries.asSequence().flatMap {
                sequenceOf(
                    it.toPair(),
                    it.key.copy(name = lib.alias + Library.ALIAS_SEPARATOR + it.key.name) to it.value,
                )
            }
        }.toMap()
    }

    override val functions: Map by lazy {
        libraries.flatMap { lib ->
            lib.functions.entries.asSequence().flatMap {
                sequenceOf(
                    it.toPair(),
                    it.key.copy(name = lib.alias + Library.ALIAS_SEPARATOR + it.key.name) to it.value,
                )
            }
        }.toMap()
    }

    override fun plus(other: Library): Runtime {
        return aliases.find { other.alias in aliases }
            ?.let { alreadyLoadedError(other) }
            ?: RuntimeImpl(libraries.asSequence() + sequenceOf(other))
    }

    override fun plus(runtime: Runtime): RuntimeImpl =
        runtime.libraries.find { it.alias in aliases }
            ?.let { alreadyLoadedError(it) }
            ?: RuntimeImpl(libraries.asSequence() + runtime.libraries.asSequence())

    override fun minus(library: Library): RuntimeImpl {
        if (library.alias in aliases) {
            noSuchALibraryError(library)
        }
        return RuntimeImpl(libraries.asSequence().filter { it.alias != library.alias })
    }

    override operator fun minus(alias: String): RuntimeImpl {
        if (alias in aliases) {
            noSuchALibraryError(alias)
        }
        return RuntimeImpl(libraries.asSequence().filter { it.alias != alias })
    }

    override operator fun minus(aliases: Iterable): RuntimeImpl {
        val toBeRemoved =
            aliases.map {
                if (it in this.aliases) {
                    noSuchALibraryError(it)
                }
                it
            }.toSet()
        return RuntimeImpl(libraries.asSequence().filterNot { it.alias in toBeRemoved })
    }

    override fun update(library: Library): RuntimeImpl =
        aliases.find { library.alias in aliases }
            ?.let { RuntimeImpl(libraries.asSequence() + sequenceOf(library)) }
            ?: throw IllegalArgumentException("A library aliased as `${library.alias}` has never been loaded")

    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (other == null || this::class != other::class) return false

        other as RuntimeImpl

        if (delegate != other.delegate) return false

        return true
    }

    override fun hashCode(): Int = libraries.hashCode()

    override fun toString(): String = "RuntimeImpl($libraries)"

    @Suppress("NOTHING_TO_INLINE")
    companion object {
        /** Utility function to handle already loaded error */
        private inline fun alreadyLoadedError(library: Library): Nothing =
            throw AlreadyLoadedLibraryException("A library aliased as `${library.alias}` has already been loaded")

        private inline fun noSuchALibraryError(library: Library): Nothing = noSuchALibraryError(library.alias)

        private inline fun noSuchALibraryError(alias: String): Nothing =
            throw NoSuchALibraryException("No library with alias `$alias` has been loaded")
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy