Skip to content

Commit

Permalink
Merge pull request #12 from kleis-technology/xp/datasource
Browse files Browse the repository at this point in the history
Feature/datasource
  • Loading branch information
pevab authored Jan 23, 2024
2 parents 0813677 + 1fa55e1 commit f19daf9
Show file tree
Hide file tree
Showing 58 changed files with 2,468 additions and 589 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class AssessCommand : CliktCommand(name = "assess", help = "Returns the unitary
override fun run() {
val files = lcaFiles(path)
val symbolTable = Loader(BasicOperations).load(files, listOf(LoaderOption.WITH_PRELUDE))
val processor = CsvProcessor(symbolTable)
val processor = CsvProcessor(path, symbolTable)
val iterator = loadRequests()
val writer = CsvResultWriter()
var first = true
Expand Down
8 changes: 6 additions & 2 deletions cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/TestCommand.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ch.kleis.lcaac.cli.cmd

import ch.kleis.lcaac.core.datasource.CsvSourceOperations
import ch.kleis.lcaac.core.math.basic.BasicOperations
import ch.kleis.lcaac.core.testing.BasicTestRunner
import ch.kleis.lcaac.core.testing.GenericFailure
Expand Down Expand Up @@ -32,12 +33,15 @@ class TestCommand : CliktCommand(name = "test", help = "Run specified tests") {

override fun run() {
val files = lcaFiles(path)
val symbolTable = Loader(BasicOperations).load(files, listOf(LoaderOption.WITH_PRELUDE))
val ops = BasicOperations
val symbolTable = Loader(ops).load(files, listOf(LoaderOption.WITH_PRELUDE))
val mapper = CoreTestMapper()
val cases = files
.flatMap { it.testDefinition() }
.map { mapper.test(it) }
val runner = BasicTestRunner<LcaLangParser.TestDefinitionContext>(symbolTable)
val runner = BasicTestRunner<LcaLangParser.TestDefinitionContext>(
symbolTable,
CsvSourceOperations(path, ops))
val results = cases.map { runner.run(it) }

results.forEach { result ->
Expand Down
41 changes: 17 additions & 24 deletions cli/src/main/kotlin/ch/kleis/lcaac/cli/cmd/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package ch.kleis.lcaac.cli.cmd
import ch.kleis.lcaac.core.lang.evaluator.EvaluatorException
import ch.kleis.lcaac.core.lang.expression.DataExpression
import ch.kleis.lcaac.core.lang.expression.EQuantityScale
import ch.kleis.lcaac.core.lang.expression.EUnitOf
import ch.kleis.lcaac.core.lang.expression.QuantityExpression
import ch.kleis.lcaac.core.math.basic.BasicNumber
import ch.kleis.lcaac.core.math.basic.BasicOperations
import ch.kleis.lcaac.grammar.CoreMapper
Expand Down Expand Up @@ -34,31 +32,26 @@ private fun lcaFile(inputStream: InputStream): LcaLangParser.LcaFileContext {
return parser.lcaFile()
}

fun parseQuantityWithDefaultUnit(s: String, defaultUnit: DataExpression<BasicNumber>): DataExpression<BasicNumber> {
fun smartParseQuantityWithDefaultUnit(s: String, defaultUnit: DataExpression<BasicNumber>): DataExpression<BasicNumber> {
val parts = s.split(" ")
return when (parts.size) {
1 -> {
val number = parts[0]
val amount = try {
parseDouble(number)
} catch (e: NumberFormatException) {
throw EvaluatorException("'$s' is not a valid quantity")
}
EQuantityScale(BasicNumber(amount), defaultUnit)
return if (parts.size == 1) {
val number = parts[0]
val amount = try {
parseDouble(number)
} catch (e: NumberFormatException) {
throw EvaluatorException("'$s' is not a valid quantity")
}
2 -> {
val lexer = LcaLangLexer(CharStreams.fromString(s))
val tokens = CommonTokenStream(lexer)
val parser = LcaLangParser(tokens)
val ctx = parser.dataExpression()
try {
CoreMapper(BasicOperations).dataExpression(ctx)
} catch (e: IllegalStateException) {
throw EvaluatorException("'$s' is not a valid quantity")
}
EQuantityScale(BasicNumber(amount), defaultUnit)
} else {
val lexer = LcaLangLexer(CharStreams.fromString(s))
val tokens = CommonTokenStream(lexer)
val parser = LcaLangParser(tokens)
val ctx = parser.dataExpression()
try {
CoreMapper(BasicOperations).dataExpression(ctx)
} catch (e: IllegalStateException) {
throw EvaluatorException("'$s' is not a valid quantity")
}
else -> throw EvaluatorException("'$s' is not a valid quantity")
}

}

52 changes: 28 additions & 24 deletions cli/src/main/kotlin/ch/kleis/lcaac/cli/csv/CsvProcessor.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package ch.kleis.lcaac.cli.csv

import ch.kleis.lcaac.cli.cmd.parseQuantityWithDefaultUnit
import ch.kleis.lcaac.cli.cmd.smartParseQuantityWithDefaultUnit
import ch.kleis.lcaac.core.assessment.ContributionAnalysisProgram
import ch.kleis.lcaac.core.datasource.CsvSourceOperations
import ch.kleis.lcaac.core.lang.SymbolTable
import ch.kleis.lcaac.core.lang.evaluator.Evaluator
import ch.kleis.lcaac.core.lang.evaluator.EvaluatorException
Expand All @@ -11,49 +12,52 @@ import ch.kleis.lcaac.core.lang.expression.QuantityExpression
import ch.kleis.lcaac.core.lang.expression.StringExpression
import ch.kleis.lcaac.core.math.basic.BasicNumber
import ch.kleis.lcaac.core.math.basic.BasicOperations
import java.io.File

class CsvProcessor(
private val symbolTable: SymbolTable<BasicNumber>,
path: File,
private val symbolTable: SymbolTable<BasicNumber>,
) {
private val ops = BasicOperations
private val evaluator = Evaluator(symbolTable, ops)
private val sourceOps = CsvSourceOperations(path, ops)
private val evaluator = Evaluator(symbolTable, ops, sourceOps)

fun process(request: CsvRequest): List<CsvResult> {
val reqName = request.processName
val reqLabels = request.matchLabels
val template =
symbolTable.getTemplate(reqName, reqLabels)
?: throw EvaluatorException("Could not get template for ${reqName}${reqLabels}")
symbolTable.getTemplate(reqName, reqLabels)
?: throw EvaluatorException("Could not get template for ${reqName}${reqLabels}")

val arguments = template.params
.mapValues { entry ->
when (val v = entry.value) {
is QuantityExpression<*> -> request[entry.key]?.let {
parseQuantityWithDefaultUnit(it, EUnitOf(v))
} ?: entry.value
.mapValues { entry ->
when (val v = entry.value) {
is QuantityExpression<*> -> request[entry.key]?.let {
smartParseQuantityWithDefaultUnit(it, EUnitOf(v))
} ?: entry.value

is StringExpression -> request[entry.key]?.let {
EStringLiteral(it)
} ?: entry.value
is StringExpression -> request[entry.key]?.let {
EStringLiteral(it)
} ?: entry.value

else -> throw EvaluatorException("$v is not a supported data expression")
}
else -> throw EvaluatorException("$v is not a supported data expression")
}
}

val trace = evaluator.trace(template, arguments)
val systemValue = trace.getSystemValue()
val entryPoint = trace.getEntryPoint()
val program = ContributionAnalysisProgram(systemValue, entryPoint)
val analysis = program.run()
return entryPoint.products
.map { output ->
val outputPort = output.product
val impacts = analysis.getUnitaryImpacts(outputPort)
CsvResult(
request,
outputPort,
impacts,
)
}
.map { output ->
val outputPort = output.product
val impacts = analysis.getUnitaryImpacts(outputPort)
CsvResult(
request,
outputPort,
impacts,
)
}
}
}
10 changes: 10 additions & 0 deletions cli/src/main/kotlin/ch/kleis/lcaac/cli/csv/Utils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package ch.kleis.lcaac.cli.csv

import ch.kleis.lcaac.core.lang.evaluator.EvaluatorException
import ch.kleis.lcaac.core.lang.expression.DataExpression
import ch.kleis.lcaac.core.lang.expression.EQuantityScale
import ch.kleis.lcaac.core.math.basic.BasicNumber
import java.lang.Double
import kotlin.NumberFormatException
import kotlin.String

30 changes: 25 additions & 5 deletions cli/src/test/kotlin/ch/kleis/lcaac/cli/cmd/UtilsKtTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package ch.kleis.lcaac.cli.cmd

import ch.kleis.lcaac.core.lang.evaluator.EvaluatorException
import ch.kleis.lcaac.core.lang.expression.EDataRef
import ch.kleis.lcaac.core.lang.expression.EQuantityMul
import ch.kleis.lcaac.core.lang.expression.EQuantityScale
import ch.kleis.lcaac.core.math.basic.BasicNumber
import ch.kleis.lcaac.core.prelude.Prelude
Expand All @@ -19,7 +20,7 @@ class UtilsKtTest {
val defaultUnit = Prelude.unitMap<BasicNumber>()["kg"]!!

// when/then
val actual = assertThrows<EvaluatorException> { parseQuantityWithDefaultUnit(s, defaultUnit) }
val actual = assertThrows<EvaluatorException> { smartParseQuantityWithDefaultUnit(s, defaultUnit) }
assertEquals("'a@bc' is not a valid quantity", actual.message)
}

Expand All @@ -30,7 +31,7 @@ class UtilsKtTest {
val defaultUnit = Prelude.unitMap<BasicNumber>()["kg"]!!

// when/then
val actual = assertThrows<EvaluatorException> { parseQuantityWithDefaultUnit(s, defaultUnit) }
val actual = assertThrows<EvaluatorException> { smartParseQuantityWithDefaultUnit(s, defaultUnit) }
assertEquals("'12 3 4' is not a valid quantity", actual.message)
}

Expand All @@ -41,7 +42,7 @@ class UtilsKtTest {
val defaultUnit = Prelude.unitMap<BasicNumber>()["kg"]!!

// when/then
val actual = assertThrows<EvaluatorException> { parseQuantityWithDefaultUnit(s, defaultUnit) }
val actual = assertThrows<EvaluatorException> { smartParseQuantityWithDefaultUnit(s, defaultUnit) }
assertEquals("'12 \$3' is not a valid quantity", actual.message)
}

Expand All @@ -52,7 +53,7 @@ class UtilsKtTest {
val defaultUnit = Prelude.unitMap<BasicNumber>()["kg"]!!

// when
val actual = parseQuantityWithDefaultUnit(s, defaultUnit)
val actual = smartParseQuantityWithDefaultUnit(s, defaultUnit)

// then
assertEquals(EQuantityScale(BasicNumber(12.0), defaultUnit), actual)
Expand All @@ -65,9 +66,28 @@ class UtilsKtTest {
val defaultUnit = Prelude.unitMap<BasicNumber>()["kg"]!!

// when
val actual = parseQuantityWithDefaultUnit(s, defaultUnit)
val actual = smartParseQuantityWithDefaultUnit(s, defaultUnit)

// then
assertEquals(EQuantityScale(BasicNumber(12.0), EDataRef("kg")), actual)
}

@Test
fun parseQuantityWithDefaultUnit_whenComplexExpression() {
// given
val s = "12.0 kg * hour"
val kg = Prelude.unitMap<BasicNumber>()["kg"]!!
val hour = Prelude.unitMap<BasicNumber>()["hour"]!!
val defaultUnit = EQuantityMul(kg, hour)

// when
val actual = smartParseQuantityWithDefaultUnit(s, defaultUnit)

// then
assertEquals(
EQuantityScale(
BasicNumber(12.0),
EQuantityMul(EDataRef("kg"), EDataRef("hour"))),
actual)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@ import ch.kleis.lcaac.core.lang.dimension.UnitSymbol
import ch.kleis.lcaac.core.lang.value.*
import ch.kleis.lcaac.core.math.basic.BasicNumber
import ch.kleis.lcaac.core.math.basic.BasicOperations
import ch.kleis.lcaac.core.prelude.Prelude
import ch.kleis.lcaac.grammar.Loader
import ch.kleis.lcaac.grammar.LoaderOption
import ch.kleis.lcaac.grammar.parser.LcaLangLexer
import ch.kleis.lcaac.grammar.parser.LcaLangParser
import io.mockk.mockk
import org.antlr.v4.runtime.CharStreams
import org.antlr.v4.runtime.CommonTokenStream
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import java.io.File

class CsvProcessorTest {

Expand All @@ -34,7 +35,8 @@ class CsvProcessorTest {
}
""".trimIndent()
val symbolTable = load(content)
val processor = CsvProcessor(symbolTable)
val path = mockk<File>()
val processor = CsvProcessor(path, symbolTable)
val request = CsvRequest(
"main",
emptyMap(),
Expand Down
2 changes: 2 additions & 0 deletions core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ dependencies {
implementation("org.apache.logging.log4j:log4j-core:$log4jVersion")
implementation("org.apache.logging.log4j:log4j-slf4j-impl:$log4jVersion")

implementation("org.apache.commons:commons-csv:1.10.0")

testImplementation(kotlin("test"))
}

Expand Down
Loading

0 comments on commit f19daf9

Please sign in to comment.