Skip to content

Commit

Permalink
Merge pull request #409 from kleis-technology/feature/ui-improvements
Browse files Browse the repository at this point in the history
feature/ui improvements
  • Loading branch information
pevab authored Feb 12, 2024
2 parents b30f768 + 46dbd18 commit 7f6c34b
Show file tree
Hide file tree
Showing 34 changed files with 333 additions and 150 deletions.
2 changes: 1 addition & 1 deletion plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ sourceSets {
}

dependencies {
implementation("ch.kleis.lcaac:core:1.6.0")
implementation("ch.kleis.lcaac:core:1.6.3")

implementation(files(layout.buildDirectory.dir("stdlib/ef3.1")) {
builtBy("generateEmissionFactors31")
Expand Down
31 changes: 17 additions & 14 deletions plugin/src/main/kotlin/ch/kleis/lcaac/plugin/language/Lca.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
tokenTypeClass="ch.kleis.lcaac.plugin.psi.LcaTokenType"

tokens=[

PACKAGE_KEYWORD = 'package'
PROCESS_KEYWORD = 'process'
SYMBOL_KEYWORD = 'symbol'
Expand Down Expand Up @@ -59,20 +60,21 @@
LOOKUP_KEYWORD = 'lookup'
DEFAULT_RECORD_KEYWORD = 'default_record'

NUMBER = 'number'
LSQBRACE = '['
RSQBRACE = ']'
LPAREN = '('
RPAREN = ')'
LBRACE = '{'
RBRACE = '}'
COMMA = ','
STRING_LITERAL = 'string-literal'
STRING_LITERAL = 'regexp:\"[^\"]*\"'
SPACE = "regexp:\s+"
COMMENT_BLOCK_START = 'comment-block-start'
COMMENT_BLOCK_END = 'comment-block-end'
COMMENT_CONTENT = 'comment-content'
COMMENT_LINE = 'comment-line'
NUMBER = 'regexp:-?[0-9]+(\.[0-9]+)?([eE][+-][0-9]+)?'
IDENTIFIER = 'regexp:[a-zA-Z_]\w*'
PLUS = "+"
MINUS = "-"
DOT = "."
Expand Down Expand Up @@ -146,7 +148,7 @@ test ::= 'test' testRef '{'
}
given ::= 'given' '{' technoInputExchange *'}'
assert ::= 'assert' '{' rangeAssertion* '}'
rangeAssertion ::= uid 'between' dataExpression 'and' dataExpression
rangeAssertion ::= uid 'between' dataExpression 'and' dataExpression { pin=2 }

/*
Substance
Expand Down Expand Up @@ -270,27 +272,28 @@ block_impacts ::= "impacts" "{" impactExchange* "}"
Exchanges
*/

technoProductExchange ::= dataExpression outputProductSpec
technoProductExchange ::= dataExpression outputProductSpec { pin=1 }

technoInputExchange ::= terminalTechnoInputExchange
| technoBlockForEach
terminalTechnoInputExchange ::= dataExpression inputProductSpec
terminalTechnoInputExchange ::= dataExpression inputProductSpec { pin=1 }
technoBlockForEach ::= 'for_each' dataRef 'from' dataSourceExpression '{' (variables | technoInputExchange)* '}' {
pin=1
implements=["ch.kleis.lcaac.plugin.language.psi.type.PsiBlockForEach"]
mixin="ch.kleis.lcaac.plugin.language.psi.mixin.PsiBlockForEachMixin"
}

bioExchange ::= terminalBioExchange
| bioBlockForEach
terminalBioExchange ::= dataExpression substanceSpec
terminalBioExchange ::= dataExpression substanceSpec { pin=1 }
bioBlockForEach ::= 'for_each' dataRef 'from' dataSourceExpression '{' (variables | bioExchange)* '}' {
implements=["ch.kleis.lcaac.plugin.language.psi.type.PsiBlockForEach"]
mixin="ch.kleis.lcaac.plugin.language.psi.mixin.PsiBlockForEachMixin"
}

impactExchange ::= terminalImpactExchange
| impactBlockForEach
terminalImpactExchange ::= dataExpression indicatorRef
terminalImpactExchange ::= dataExpression indicatorRef { pin=1 }
impactBlockForEach ::= 'for_each' dataRef 'from' dataSourceExpression '{' (variables | impactExchange)* '}' {
implements=["ch.kleis.lcaac.plugin.language.psi.type.PsiBlockForEach"]
mixin="ch.kleis.lcaac.plugin.language.psi.mixin.PsiBlockForEachMixin"
Expand Down Expand Up @@ -331,11 +334,11 @@ exponentialQuantityExpression ::= dataExpression "^" NUMBER { extends=dataExpres
parenQuantityExpression ::= "(" dataExpression ")" { extends=dataExpression }
scaleQuantityExpression ::= NUMBER dataExpression { extends=dataExpression methods=[scale="NUMBER"]}
stringExpression ::= STRING_LITERAL { extends=dataExpression }
sliceExpression ::= dataRef '.' columnRef { extends=dataExpression }
sliceExpression ::= dataRef '.' columnRef { pin=2 extends=dataExpression }
recordExpression ::= (opDefaultRecord | opLookup) dataSourceExpression { extends=dataExpression }
opDefaultRecord ::= 'default_record' 'from'
opDefaultRecord ::= 'default_record' 'from' { pin=1 }
opLookup ::= 'lookup'
colExpression ::= 'sum' '(' dataSourceExpression ',' columnRef ('*' columnRef)* ')' { extends=dataExpression }
colExpression ::= 'sum' '(' dataSourceExpression ',' columnRef ('*' columnRef)* ','? ')' { pin=1 extends=dataExpression }

/*
Data source expression
Expand All @@ -344,7 +347,7 @@ colExpression ::= 'sum' '(' dataSourceExpression ',' columnRef ('*' columnRef)*
dataSourceExpression ::= dataSourceRef rowFilter?
rowFilter ::= MATCH_KEYWORD rowSelector
| MATCH_KEYWORD LPAREN ( rowSelector (COMMA rowSelector)* COMMA? ) RPAREN
rowSelector ::= columnRef EQUAL dataExpression
rowSelector ::= columnRef EQUAL dataExpression { pin=1 }


/*
Expand Down Expand Up @@ -433,13 +436,13 @@ processTemplateSpec ::= "from" processRef ("(" comma_sep_arguments? ")")? matchL
implements=["ch.kleis.lcaac.plugin.language.psi.type.spec.PsiProcessTemplateSpec"]
mixin="ch.kleis.lcaac.plugin.language.psi.mixin.spec.PsiProcessTemplateSpecMixin"
}
matchLabels ::= "match" "(" comma_sep_label_selectors? ")"
matchLabels ::= "match" ( labelSelector | "(" comma_sep_label_selectors? ")")

private comma_sep_label_selectors ::= labelSelector ("," labelSelector)* ","?
labelSelector ::= labelRef "=" dataExpression
labelSelector ::= labelRef "=" dataExpression { pin=1 }

private comma_sep_arguments ::= argument ("," argument)* ","?
argument ::= parameterRef "=" dataExpression
argument ::= parameterRef "=" dataExpression { pin=1 }

substanceSpec ::= substanceRef ("(" compartmentField ("," subCompartmentField )? ")")? {
implements=["ch.kleis.lcaac.plugin.language.psi.type.spec.PsiSubstanceSpec"]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package ch.kleis.lcaac.plugin.language.ide.insight

import ch.kleis.lcaac.plugin.language.psi.type.PsiAssignment
import ch.kleis.lcaac.plugin.language.psi.type.PsiColumnDefinition
import ch.kleis.lcaac.plugin.language.psi.type.PsiGlobalAssignment
import ch.kleis.lcaac.plugin.language.psi.type.ref.PsiColumnRef
import ch.kleis.lcaac.plugin.language.psi.type.ref.PsiDataRef
import ch.kleis.lcaac.plugin.language.psi.type.unit.PsiUnitDefinition
import com.intellij.codeInspection.ProblemHighlightType
Expand All @@ -23,14 +25,20 @@ object AnnotatorHelper {
.create()

fun isAssignmentReceiver(element: PsiDataRef) =
isUnitDefName(element) || isLeftHandSideOfGlobalAssignement(element) || isLeftHandSideOfLocalAssignement(element)
isUnitDefName(element) || isLeftHandSideOfGlobalAssignment(element) || isLeftHandSideOfLocalAssignment(element)

fun isColumnDefinitionReceiver(element: PsiColumnRef) =
isLeftHandSideOfColumnDefinition(element)

private fun isUnitDefName(element: PsiDataRef): Boolean =
element.parent is PsiUnitDefinition

private fun isLeftHandSideOfGlobalAssignement(element: PsiDataRef): Boolean =
private fun isLeftHandSideOfGlobalAssignment(element: PsiDataRef): Boolean =
element.parent is PsiGlobalAssignment && element.nextSibling != null

private fun isLeftHandSideOfLocalAssignement(element: PsiDataRef): Boolean =
private fun isLeftHandSideOfLocalAssignment(element: PsiDataRef): Boolean =
element.parent is PsiAssignment && element.nextSibling != null

private fun isLeftHandSideOfColumnDefinition(element: PsiColumnRef): Boolean =
element.parent is PsiColumnDefinition && element.nextSibling != null
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,14 @@ class LcaBioExchangeAnnotator : Annotator {
}

private fun checkReferenceResolution(element: LcaTerminalBioExchange, holder: AnnotationHolder) {
val target = element.substanceSpec.reference?.resolve()
val substanceSpec = element.substanceSpec
if (substanceSpec == null) {
annotateErrWithMessage(element, holder, "missing substance")
return
}
val target = substanceSpec.reference?.resolve()
if (target == null || target !is PsiSubstance) {
val spec = element.substanceSpec
annotateWarnWithMessage(spec, holder, "unresolved substance ${render(spec)}")
annotateWarnWithMessage(substanceSpec, holder, "unresolved substance ${render(substanceSpec)}")
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package ch.kleis.lcaac.plugin.language.ide.insight

import ch.kleis.lcaac.plugin.language.ide.insight.AnnotatorHelper.annotateErrWithMessage
import ch.kleis.lcaac.plugin.language.ide.insight.AnnotatorHelper.isColumnDefinitionReceiver
import ch.kleis.lcaac.plugin.language.psi.type.ref.PsiColumnRef
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.lang.annotation.Annotator
import com.intellij.psi.PsiElement

// TODO: Test me
class LcaColumnDefinitionAnnotator : Annotator {
override fun annotate(element: PsiElement, holder: AnnotationHolder) {
if (element is PsiColumnRef && isColumnDefinitionReceiver(element)) {
if (element.reference.multiResolve(false).size > 1) {
annotateErrWithMessage(element, holder, "This name is already defined.")
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package ch.kleis.lcaac.plugin.language.ide.insight

import ch.kleis.lcaac.plugin.language.ide.insight.AnnotatorHelper.annotateErrWithMessage
import ch.kleis.lcaac.plugin.language.ide.insight.AnnotatorHelper.isColumnDefinitionReceiver
import ch.kleis.lcaac.plugin.language.psi.type.ref.PsiColumnRef
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.lang.annotation.Annotator
import com.intellij.psi.PsiElement

// TODO: Test me
class LcaDataColumnRefAnnotator : Annotator {
override fun annotate(element: PsiElement, holder: AnnotationHolder) {
if (element is PsiColumnRef && !isColumnDefinitionReceiver(element)) {
if (element.reference.resolve() == null) {
annotateErrWithMessage(element, holder, "Unknown column.")
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,18 @@ class LcaProcessAnnotator : Annotator {
return
}

val productNames = products.map { it.outputProductSpec.name }
val productNames = products.map {
val outputProductSpec = it.outputProductSpec
if (outputProductSpec == null) {
annotateErrWithMessage(it, holder, "missing product")
return
}
outputProductSpec.name
}
val productsWithoutAllocationFactors = products
.filter { it.outputProductSpec.allocateField == null }
.filter {
it.outputProductSpec?.allocateField == null
}
if (productsWithoutAllocationFactors.isNotEmpty()) {
annotateErrWithMessage(
element.blockProductsList.first(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package ch.kleis.lcaac.plugin.language.ide.insight

import ch.kleis.lcaac.plugin.language.ide.insight.AnnotatorHelper.annotateErrWithMessage
import ch.kleis.lcaac.plugin.language.psi.type.PsiColumnDefinition
import ch.kleis.lcaac.plugin.language.type_checker.PsiLcaTypeChecker
import ch.kleis.lcaac.plugin.language.type_checker.PsiTypeCheckException
import ch.kleis.lcaac.plugin.psi.LcaRowSelector
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.lang.annotation.Annotator
import com.intellij.psi.PsiElement

// TODO: Test me
class LcaRowSelectorAnnotator : Annotator {
override fun annotate(element: PsiElement, holder: AnnotationHolder) {
if (element is LcaRowSelector) {
val columnRef = element.columnRef
val dataExpression = element.dataExpression
if (dataExpression == null) {
annotateErrWithMessage(element, holder, "Missing right-hand side")
return
}
val columnDefinition = columnRef.reference.resolve()
if (columnDefinition !is PsiColumnDefinition) {
annotateErrWithMessage(element, holder, "Unknown column '${columnRef.name}'")
return
}
val defaultValue = columnDefinition.getValue()
val checker = PsiLcaTypeChecker()
val defaultValueType = try {
checker.check(defaultValue)
} catch (e: PsiTypeCheckException) {
annotateErrWithMessage(element, holder, "Could not determine the type of column '${columnRef.name}'")
return
}
val dataType = try {
checker.check(dataExpression)
} catch (e: PsiTypeCheckException) {
annotateErrWithMessage(element, holder, "Could not determine the type of right-hand side")
return
}
if (dataType != defaultValueType) {
annotateErrWithMessage(element, holder, "Expected ${defaultValueType}, found $dataType")
return
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package ch.kleis.lcaac.plugin.language.ide.insight

import ch.kleis.lcaac.plugin.language.ide.insight.AnnotatorHelper.annotateErrWithMessage
import ch.kleis.lcaac.plugin.psi.LcaSliceExpression
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.lang.annotation.Annotator
import com.intellij.psi.PsiElement

// TODO: Test me
class LcaSliceExpressionAnnotator : Annotator {
override fun annotate(element: PsiElement, holder: AnnotationHolder) {
if (element is LcaSliceExpression) {
val columnRef = element.columnRef
if (columnRef == null) {
annotateErrWithMessage(element, holder, "Missing column reference")
} else if (columnRef.reference.resolve() == null) {
annotateErrWithMessage(element, holder, "Unknown column '${columnRef.name}'")
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,20 @@ class LcaTerminalTechnoInputExchangeAnnotator : Annotator {
if (element !is LcaTerminalTechnoInputExchange) {
return
}
val inputProductSpec = element.inputProductSpec
if (inputProductSpec == null) {
annotateErrWithMessage(element, holder, "missing input product")
return
}
val targets =
(element.inputProductSpec.reference as OutputProductReferenceFromPsiInputProductSpec)
(inputProductSpec.reference as OutputProductReferenceFromPsiInputProductSpec)
.multiResolve(false)
.filter { it.element is LcaOutputProductSpec }

when (targets.size) {
0 -> {
val specString = specToStr(element.inputProductSpec)
annotateWarnWithMessage(element.inputProductSpec, holder, "Could not resolve $specString")
val specString = specToStr(inputProductSpec)
annotateWarnWithMessage(inputProductSpec, holder, "Could not resolve $specString")
}
1 -> {
val checker = PsiLcaTypeChecker()
Expand All @@ -37,8 +42,8 @@ class LcaTerminalTechnoInputExchangeAnnotator : Annotator {
}
}
else -> {
val specString = specToStr(element.inputProductSpec)
annotateWarnWithMessage(element.inputProductSpec, holder, "Multiple candidates found for $specString")
val specString = specToStr(inputProductSpec)
annotateWarnWithMessage(inputProductSpec, holder, "Multiple candidates found for $specString")
}
}
}
Expand Down
Loading

0 comments on commit 7f6c34b

Please sign in to comment.