Skip to content

Commit

Permalink
core + grammar: import resolver
Browse files Browse the repository at this point in the history
  • Loading branch information
Peva Blanchard committed Oct 29, 2023
1 parent 3e37541 commit d97c4bc
Show file tree
Hide file tree
Showing 13 changed files with 126 additions and 109 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ class LcaExpressionReducer<Q>(
expression.compartment,
expression.subCompartment,
expression.referenceUnit?.let { dataExpressionReducer.reduce(it) },
from = expression.from, // TODO: Should we reduce from expression? (e.g., when arguments)
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ class CompleteTerminals<Q>(
return (EProcess.biosphere<Q>() compose Every.list())
.modify(this) { exchange ->
val referenceUnit = exchangeReferenceUnit(exchange)

EBioExchange.substance<Q>()
.modify(exchange) {
val s = if (it.referenceUnit == null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package ch.kleis.lcaac.core.lang.register

import ch.kleis.lcaac.core.lang.expression.PackageExpression
import ch.kleis.lcaac.core.lang.expression.EImport

data class ImportKey(val name: String)

typealias ImportRegister<Q> = Register<ImportKey, PackageExpression<Q>>
typealias ImportRegister<Q> = Register<ImportKey, EImport<Q>>
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package ch.kleis.lcaac.core.lang.resolver

import ch.kleis.lcaac.core.lang.expression.EImport
import ch.kleis.lcaac.core.lang.expression.EPackage
import ch.kleis.lcaac.core.lang.expression.SubstanceType

interface ImportResolver<Q> {
fun resolve(import: EImport<Q>, hint: ImportHint? = null): EPackage<Q>
}

/*
Hint allows further optimizations.
E.g., when importing a substance from EF 3.1,
no need to include all the substances in the retrieved package.
*/

sealed interface ImportHint

data class HintData(
val name: String
) : ImportHint

data class HintProcess(
val name: String,
val labels: Map<String, String> = emptyMap(),
) : ImportHint

data class HintSubstance(
val name: String,
val type: SubstanceType,
val compartment: String,
val subCompartment: String? = null,
) : ImportHint

This file was deleted.

61 changes: 45 additions & 16 deletions core/src/main/kotlin/ch/kleis/lcaac/core/lang/resolver/Resolver.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,42 @@ package ch.kleis.lcaac.core.lang.resolver

import ch.kleis.lcaac.core.lang.evaluator.EvaluatorException
import ch.kleis.lcaac.core.lang.expression.*
import ch.kleis.lcaac.core.lang.register.ImportKey

class Resolver<Q>(
val rootPkg: EPackage<Q>,
private val pkgResolver: PkgResolver<Q>,
private val importResolver: ImportResolver<Q>,
) {
fun withRoot(pkg: EPackage<Q>): Resolver<Q> = Resolver(pkg, pkgResolver)
fun withRoot(pkg: EPackage<Q>): Resolver<Q> = Resolver(pkg, importResolver)

private fun fetchPkg(e: PackageImportExpression<Q>?, hint: ImportHint? = null): EPackage<Q> {
return when (e) {
null -> rootPkg
is EImportRef -> {
val e2 = rootPkg.imports[ImportKey(e.name)] ?: return rootPkg
importResolver.resolve(e2, hint)
}

is EImport -> importResolver.resolve(e, hint)
}
}

private fun fetchPkg(e: FromExpression<Q>?, hint: ImportHint? = null): EPackage<Q> {
return when (e) {
is FromPackage -> fetchPkg(e.pkg, hint)
is FromProcess -> fetchPkg(e.pkg, hint)
null -> rootPkg
}
}

fun resolve(dataRef: EDataRef<Q>): DataExpression<Q>? {
val pkg = if (dataRef.from == null) rootPkg else pkgResolver.resolve(dataRef)
val pkg = fetchPkg(dataRef.from, HintData(dataRef.name))
return pkg.getData(dataRef.name)
}

fun resolve(spec: EProductSpec<Q>): EProcessTemplate<Q>? {
val pkg = when(spec.from) {
null -> rootPkg
else -> pkgResolver.resolve(spec)
}
if (spec.from !is FromProcess) {
val pkg = fetchPkg(spec.from)
val matches = pkg.getAllTemplatesByProductName(spec.name)
return when (matches.size) {
0 -> null
Expand All @@ -30,11 +48,18 @@ class Resolver<Q>(

val name = spec.from.name
val labels = spec.from.matchLabels.elements.mapValues {
when (val v = it.value) {
is EStringLiteral -> v.value
else -> throw EvaluatorException("$v is not a valid label value")
}
when (val v = it.value) {
is EStringLiteral -> v.value
else -> throw EvaluatorException("$v is not a valid label value")
}
}
val pkg = fetchPkg(
spec.from,
HintProcess(
name,
labels,
)
)
return pkg.getTemplate(name, labels)?.let { candidate ->
val providedProducts = candidate.body.products.map { it.product.name }
if (!providedProducts.contains(spec.name)) {
Expand All @@ -46,13 +71,17 @@ class Resolver<Q>(
}

fun resolve(spec: ESubstanceSpec<Q>): ESubstanceCharacterization<Q>? {
val pkg = if (spec.from == null) rootPkg else pkgResolver.resolve(spec)
val name = spec.name
val type = spec.type ?: return null
val compartment = spec.compartment ?: return null

return spec.subCompartment?.let { subCompartment ->
pkg.getSubstanceCharacterization(name, type, compartment, subCompartment)
} ?: pkg.getSubstanceCharacterization(name, type, compartment)
val subCompartment = spec.subCompartment
val pkg = fetchPkg(
spec.from,
HintSubstance(
name, type, compartment, subCompartment
),
)
return pkg.getSubstanceCharacterization(name, type, compartment, subCompartment)
?: pkg.getSubstanceCharacterization(name, type, compartment)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,9 @@ class EvaluatorTest {
products = listOf(
ETechnoExchange(
QuantityFixture.oneKilogram,
ProductFixture.salad,
ProductFixture.salad.copy(
from = FromProcess("carrot_production", pkg = EImport("default"))
),
)
),
biosphere = listOf(
Expand All @@ -398,6 +400,7 @@ class EvaluatorTest {
"propanol",
compartment = "air",
type = SubstanceType.RESOURCE,
from = EImport("default")
)
)
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import ch.kleis.lcaac.core.lang.value.BioExchangeValue
import ch.kleis.lcaac.core.lang.value.ImpactValue
import ch.kleis.lcaac.core.lang.value.IndicatorValue
import ch.kleis.lcaac.core.lang.value.SubstanceCharacterizationValue
import ch.kleis.lcaac.core.math.basic.BasicNumber
import ch.kleis.lcaac.core.math.basic.BasicOperations
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
Expand All @@ -25,9 +26,10 @@ class CompleteTerminalsTest {
EBioExchange(QuantityFixture.oneKilogram, ESubstanceSpec("co2"))
),
)
val resolver = ResolverFixture.alwaysResolveTo(EPackage.empty<BasicNumber>())

// when
val actual = CompleteTerminals(ops).apply(process)
val actual = CompleteTerminals(resolver, ops).apply(process)

// then
val expected =
Expand All @@ -38,7 +40,8 @@ class CompleteTerminalsTest {
QuantityFixture.oneKilogram,
ESubstanceSpec(
"co2",
referenceUnit = QuantityFixture.oneKilogram
referenceUnit = QuantityFixture.oneKilogram,
from = EImport("default"),
)
)
),
Expand All @@ -55,9 +58,10 @@ class CompleteTerminalsTest {
EImpact(QuantityFixture.oneKilogram, EIndicatorSpec("cc"))
)
)
val resolver = ResolverFixture.alwaysResolveTo(EPackage.empty<BasicNumber>())

// when
val actual = with(ToValue(BasicOperations)) { CompleteTerminals(ops).apply(expression).toValue() }
val actual = with(ToValue(BasicOperations)) { CompleteTerminals(resolver, ops).apply(expression).toValue() }

// then
val expected = SubstanceCharacterizationValue(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,17 @@
package ch.kleis.lcaac.core.lang.fixture

import ch.kleis.lcaac.core.lang.expression.*
import ch.kleis.lcaac.core.lang.resolver.PkgResolver
import ch.kleis.lcaac.core.lang.resolver.ImportHint
import ch.kleis.lcaac.core.lang.resolver.ImportResolver
import ch.kleis.lcaac.core.lang.resolver.Resolver

class ResolverFixture {
companion object {
fun <Q> alwaysResolveTo(rootPkg: EPackage<Q>): Resolver<Q> {
return Resolver(
rootPkg,
object : PkgResolver<Q> {
override fun resolve(spec: EProductSpec<Q>): EPackage<Q> {
return rootPkg
}

override fun resolve(spec: ESubstanceSpec<Q>): EPackage<Q> {
return rootPkg
}

override fun resolve(dataRef: EDataRef<Q>): EPackage<Q> {
return rootPkg
}

override fun resolve(pkg: PackageExpression<Q>): EPackage<Q> {
object : ImportResolver<Q> {
override fun resolve(import: EImport<Q>, hint: ImportHint?): EPackage<Q> {
return rootPkg
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ch.kleis.lcaac.core.lang.fixture

import ch.kleis.lcaac.core.lang.expression.EImport
import ch.kleis.lcaac.core.lang.expression.ESubstanceSpec
import ch.kleis.lcaac.core.lang.expression.SubstanceType

Expand All @@ -12,6 +13,7 @@ class SubstanceFixture {
"air",
null,
QuantityFixture.oneKilogram,
from = EImport("default"),
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package ch.kleis.lcaac.grammar

import ch.kleis.lcaac.core.lang.evaluator.EvaluatorException
import ch.kleis.lcaac.core.lang.expression.EImport
import ch.kleis.lcaac.core.lang.expression.EPackage
import ch.kleis.lcaac.core.lang.resolver.ImportHint
import ch.kleis.lcaac.core.lang.resolver.ImportResolver
import ch.kleis.lcaac.core.math.QuantityOperations

class CoreImportResolver<Q>(
sourceSet: SourceSet,
ops: QuantityOperations<Q>,
loader: PkgLoader<Q> = PkgLoader(sourceSet, ops),
) : ImportResolver<Q> {
private val pkgs = sourceSet.pkgNames()
.associateWith { loader.load(it) }

// We ignore hint for now
override fun resolve(import: EImport<Q>, hint: ImportHint?): EPackage<Q> {
return pkgs[import.name] ?: throw EvaluatorException("unknown package ${import.name}")
}
}
55 changes: 0 additions & 55 deletions grammar/src/main/kotlin/ch/kleis/lcaac/grammar/CorePkgResolver.kt

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
package ch.kleis.lcaac.grammar

import ch.kleis.lcaac.core.lang.expression.*
import ch.kleis.lcaac.core.lang.resolver.PkgResolver
import ch.kleis.lcaac.core.lang.resolver.ImportHint
import ch.kleis.lcaac.core.lang.resolver.ImportResolver
import ch.kleis.lcaac.core.lang.resolver.Resolver

class ResolverFixture {
companion object {
fun <Q> alwaysResolveTo(rootPkg: EPackage<Q>): Resolver<Q> = Resolver(
rootPkg,
object : PkgResolver<Q> {
override fun resolve(spec: EProductSpec<Q>): EPackage<Q> = rootPkg
override fun resolve(spec: ESubstanceSpec<Q>): EPackage<Q> = rootPkg
override fun resolve(dataRef: EDataRef<Q>): EPackage<Q> = rootPkg
override fun resolve(pkg: PackageExpression<Q>): EPackage<Q> = rootPkg
object : ImportResolver<Q> {
override fun resolve(import: EImport<Q>, hint: ImportHint?): EPackage<Q> {
return rootPkg
}
}
)
}
Expand Down

0 comments on commit d97c4bc

Please sign in to comment.