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

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

package it.unibo.tuprolog.solve.library

import it.unibo.tuprolog.core.operators.OperatorSet
import it.unibo.tuprolog.solve.Signature
import it.unibo.tuprolog.solve.function.PrologFunction
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 kotlin.js.JsName

/** A class representing an agglomerate of libraries with an alias */
class Libraries(libraries: Sequence) :
    LibraryGroup,
    Map by (libraries.map { it.alias to it }.toMap()) {

    constructor(vararg library: AliasedLibrary) : this(library.asSequence())
    constructor(libraries: Iterable) : this(libraries.asSequence())

    /** All library aliases of libraries included in this library group */
    @JsName("libraryAliases")
    val libraryAliases: Set
        inline get() = keys

    override val libraries: Collection
        get() = values.toList()

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

    override val theory: Theory by lazy {
        Theory.indexedOf(libraries.flatMap { it.theory.clauses.asSequence() })
    }

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

    override fun plus(library: AliasedLibrary): Libraries =
        libraryAliases.find { library.alias in libraryAliases }
            ?.let { alreadyLoadedError(library) }
            ?: Libraries(libraries.asSequence() + sequenceOf(library))

    override fun plus(libraryGroup: LibraryGroup): Libraries =
        libraryGroup.libraries.find { it.alias in libraryAliases }
            ?.let { alreadyLoadedError(it) }
            ?: Libraries(libraries.asSequence() + libraryGroup.libraries.asSequence())

    override fun minus(library: AliasedLibrary): Libraries {
        if (library.alias in libraryAliases) {
            noSuchALibraryError(library)
        }
        return Libraries(libraries.asSequence().filter { it.alias != library.alias })
    }

    @JsName("minusAlias")
    operator fun minus(alias: String): Libraries {
        if (alias in libraryAliases) {
            noSuchALibraryError(alias)
        }
        return Libraries(libraries.asSequence().filter { it.alias != alias })
    }

    @JsName("minusAliases")
    operator fun minus(aliases: Iterable): Libraries {
        val toBeRemoved = aliases.map {
            if (it in libraryAliases) {
                noSuchALibraryError(it)
            }
            it
        }.toSet()
        return Libraries(libraries.asSequence().filterNot { it.alias in toBeRemoved })
    }

    override fun update(library: AliasedLibrary): Libraries =
        libraryAliases.find { library.alias in libraryAliases }
            ?.let { Libraries(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 Libraries

        if (libraries != other.libraries) return false

        return true
    }

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

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

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

        private fun noSuchALibraryError(library: AliasedLibrary): Nothing =
            noSuchALibraryError(library.alias)

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




© 2015 - 2025 Weber Informatics LLC | Privacy Policy