diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index 782b34134..e632420f5 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -4,7 +4,7 @@
-
+
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
index 0f0ffdcee..080a60abe 100644
--- a/.idea/jarRepositories.xml
+++ b/.idea/jarRepositories.xml
@@ -74,7 +74,17 @@
-
+
+
+
+
+
+
+
+
+
+
+
-
\ No newline at end of file
+
diff --git a/.idea/misc.xml b/.idea/misc.xml
index ec7ea80cb..9c9cdbfc0 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -7,7 +7,7 @@
-
+
\ No newline at end of file
diff --git a/.idea/runConfigurations/AbstractIntEqSfcAppKt.xml b/.idea/runConfigurations/AbstractIntEqSfcAppKt.xml
index 28730e671..cf3683857 100644
--- a/.idea/runConfigurations/AbstractIntEqSfcAppKt.xml
+++ b/.idea/runConfigurations/AbstractIntEqSfcAppKt.xml
@@ -1,12 +1,8 @@
-
-
-
-
-
-
-
+
+
+
diff --git a/.idea/runConfigurations/Monitor_LinRe.xml b/.idea/runConfigurations/Monitor_LinRe.xml
index b4dab67d6..72f1a2bd4 100644
--- a/.idea/runConfigurations/Monitor_LinRe.xml
+++ b/.idea/runConfigurations/Monitor_LinRe.xml
@@ -1,12 +1,8 @@
-
-
-
-
-
-
-
+
+
+
diff --git a/.idea/runConfigurations/UnwindODSApp.xml b/.idea/runConfigurations/UnwindODSApp.xml
index caddf42d0..d7a518993 100644
--- a/.idea/runConfigurations/UnwindODSApp.xml
+++ b/.idea/runConfigurations/UnwindODSApp.xml
@@ -1,12 +1,8 @@
-
-
-
-
-
-
-
+
+
+
diff --git a/exec/src/main/kotlin/edu/kit/iti/formal/automation/Kastel.kt b/exec/src/main/kotlin/edu/kit/iti/formal/automation/Kastel.kt
index 603d068db..1e4757a8b 100644
--- a/exec/src/main/kotlin/edu/kit/iti/formal/automation/Kastel.kt
+++ b/exec/src/main/kotlin/edu/kit/iti/formal/automation/Kastel.kt
@@ -111,7 +111,7 @@ object KastelDemonstrator {
object AssignmentDScratch : STCodeTransformation, AstMutableVisitor() {
override fun transform(stBody: StatementList): StatementList = stBody.accept(this) as StatementList
override fun visit(assignmentStatement: AssignmentStatement): Statement {
- if ((assignmentStatement.location as SymbolicReference).identifier == "dScratch") {
+ if (assignmentStatement.location.identifier == "dScratch") {
return StatementList()
}
return assignmentStatement
@@ -322,7 +322,7 @@ object SeqParamsActiveStep : CodeTransformation, AstMutableVisitor() {
if (sub.identifier == "Sequence" && sub.sub?.identifier == "iActStep") {
return SymbolicReference("ActStep", symbolicReference.sub)
}
- } catch (e: ClassCastException) {
+ } catch (_: ClassCastException) {
}
}
@@ -361,7 +361,7 @@ object RemoveVSObj : STCodeTransformation, AstMutableVisitor() {
override fun transform(stBody: StatementList) = stBody.accept(this) as StatementList
override fun visit(assignmentStatement: AssignmentStatement): Statement {
- val ident = (assignmentStatement.location as SymbolicReference).identifier
+ val ident = assignmentStatement.location.identifier
return if (ident == "VSObj_McFaultDescription")
return StatementList()
else assignmentStatement
diff --git a/geteta/examples/NewFile.tt.txt b/geteta/examples/NewFile.gtt
similarity index 100%
rename from geteta/examples/NewFile.tt.txt
rename to geteta/examples/NewFile.gtt
diff --git a/geteta/src/main/antlr/TestTableLanguageLexer.g4 b/geteta/src/main/antlr/TestTableLanguageLexer.g4
index dbedf2e6d..cad4f8f68 100644
--- a/geteta/src/main/antlr/TestTableLanguageLexer.g4
+++ b/geteta/src/main/antlr/TestTableLanguageLexer.g4
@@ -17,6 +17,8 @@ public SyntaxErrorReporter getErrorReporter() { return errorReporter;}
public boolean relational = false;
}
+CONTRACT: 'contract';
+AUTOMATON: 'automaton';
TCONST: 'timeconst';
INHERIT_FROM:'\\inherit_from';
DOT:'.';
diff --git a/geteta/src/main/antlr/TestTableLanguageParser.g4 b/geteta/src/main/antlr/TestTableLanguageParser.g4
index 8781f17ba..854c1223c 100644
--- a/geteta/src/main/antlr/TestTableLanguageParser.g4
+++ b/geteta/src/main/antlr/TestTableLanguageParser.g4
@@ -21,7 +21,8 @@ public SyntaxErrorReporter getErrorReporter() { return errorReporter;}
}
//structure level
-file : table* EOF;
+file : (ca | table)* EOF;
+
table : tableHeader LBRACE
(inheritance_signature)*
(signature | freeVariable | column | decl_time_const)*
@@ -31,6 +32,41 @@ table : tableHeader LBRACE
RBRACE
;
+ca: CONTRACT AUTOMATON name=IDENTIFIER
+ LBRACE
+ (inheritance_signature)*
+ (signature | freeVariable | column | decl_time_const)*
+ opts?
+ contract*
+ state*
+ function*
+ RBRACE
+;
+
+state:
+ STATE LBRACE contract* RBRACE
+;
+
+contract: CONTRACT
+ ( name=intOrId
+ | LBRACE
+ ( ASSUME (EQUALS|COLON) valuesOrFormula
+ | ASSERT (EQUALS|COLON) valuesOrFormula
+ )
+ goto_*
+ RBRACE
+ )
+;
+
+valuesOrFormula:
+ expr
+ | LBRACE
+ (kc osem)*
+ RBRACE
+;
+
+
+
tableHeader:
{relational=false;} TABLE name=IDENTIFIER #tableHeaderFunctional
| RELATIONAL {relational=true; } TABLE name=IDENTIFIER LPAREN
diff --git a/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/apps/monitor.kt b/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/apps/monitor.kt
index 341bb75c7..262b92ad7 100644
--- a/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/apps/monitor.kt
+++ b/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/apps/monitor.kt
@@ -10,6 +10,7 @@ import edu.kit.iti.formal.automation.testtables.model.ConstraintVariable
import edu.kit.iti.formal.automation.testtables.monitor.*
import edu.kit.iti.formal.util.info
import java.io.File
+import java.util.*
/**
*
@@ -39,7 +40,7 @@ class MonitorApp : CliktCommand(name = "ttmonitor",
val format by option("--format", "-f", help = "code format, possible values: " +
CodeOutput.entries.joinToString(",") { it.name })
- .convert { CodeOutput.valueOf(it.toUpperCase()) }
+ .convert { CodeOutput.valueOf(it.uppercase(Locale.getDefault())) }
.default(CodeOutput.CPP)
val disableCombinedMonitor by option("--disable-combined",
diff --git a/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/apps/print.kt b/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/apps/print.kt
index 336e33b08..07b508944 100644
--- a/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/apps/print.kt
+++ b/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/apps/print.kt
@@ -14,6 +14,7 @@ import edu.kit.iti.formal.automation.testtables.print.LatexTablePrinter
import edu.kit.iti.formal.automation.testtables.print.TextTablePrinter
import edu.kit.iti.formal.util.CodeWriter
import java.io.OutputStreamWriter
+import java.util.*
/**
*
@@ -29,7 +30,7 @@ class PrinterApp : CliktCommand(name="ttprint", help = "generate print files for
enum class Format { HTML, LATEX, TEXT }
val format by option("-f", "--format")
- .convert { Format.valueOf(it.toUpperCase()) }
+ .convert { Format.valueOf(it.uppercase(Locale.getDefault())) }
.default(Format.LATEX)
val output by option("--output",
diff --git a/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/apps/synthesis.kt b/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/apps/synthesis.kt
index fed3625cf..1e05edc13 100644
--- a/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/apps/synthesis.kt
+++ b/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/apps/synthesis.kt
@@ -29,6 +29,8 @@ import org.antlr.v4.runtime.CharStreams
import org.antlr.v4.runtime.CommonTokenStream
import java.io.File
import java.nio.file.Paths
+import java.util.*
+import kotlin.collections.HashMap
import kotlin.math.max
/**
@@ -65,7 +67,7 @@ class SynthesisApp : CliktCommand(
private val outputFunctionStrategy by option("--row-selection-strategy",
help = "Strategy for choosing output function when multiple rows are active")
- .choice(enumValues().associateBy { it.name.toLowerCase() })
+ .choice(enumValues().associateBy { it.name.lowercase(Locale.getDefault()) })
.default(OutputFunctionStrategy.ASSUME_ORTHOGONAL)
override fun run() {
@@ -881,11 +883,11 @@ class ExpressionSynthesizer(private val pythonExecutable: String = "python") {
"${ctx.identifier().accept(this)} = ${ctx.expr().accept(this)}"
override fun visitExpr(ctx: IteLanguageParser.ExprContext): String =
- ctx.iteExpr()?.accept(this)
- ?: ctx.expr()?.let { "(not ${it.accept(this)})" }
- ?: ctx.identifier()?.accept(this)
- ?: ctx.BOOLEAN()?.text?.toLowerCase()
- ?: ctx.INTEGER()!!.text
+ ctx.iteExpr()?.accept(this)
+ ?: ctx.expr()?.let { "(not ${it.accept(this)})" }
+ ?: ctx.identifier()?.accept(this)
+ ?: ctx.BOOLEAN()?.text?.lowercase(Locale.getDefault())
+ ?: ctx.INTEGER()!!.text
override fun visitIteExpr(ctx: IteLanguageParser.IteExprContext): String =
iteExprCache.getOrPut(
diff --git a/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/builder/miter.kt b/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/builder/miter.kt
index 23df40a0e..53bae9b76 100644
--- a/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/builder/miter.kt
+++ b/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/builder/miter.kt
@@ -31,6 +31,9 @@ import edu.kit.iti.formal.util.CodeWriter
import edu.kit.iti.formal.util.meta
import java.io.File
import java.io.PrintWriter
+import java.util.*
+import kotlin.collections.ArrayList
+import kotlin.collections.HashMap
import kotlin.math.abs
data class ReactiveProgram(
@@ -52,7 +55,7 @@ private fun createNext(t: Transition): SMVExpr {
} else {
val inputExpr = (t.from as RowState).row.inputExpr.values.conjunction(SLiteral.TRUE)
- val outputExpr = (t.from as RowState).row.outputExpr.values.conjunction(SLiteral.TRUE)
+ val outputExpr = t.from.row.outputExpr.values.conjunction(SLiteral.TRUE)
when (t.type) {
TransitionType.ACCEPT ->
@@ -152,7 +155,7 @@ class GttMiterConstruction(val gtt: GeneralizedTestTable,
.or(SVariable(err.name, SMVTypes.BOOLEAN).not())
target.body.add("__INV__" assignTo invAssign.translateToSt())
val assert = SpecialCommentFactory
- .createAssert(SymbolicReference("__INV__"));
+ .createAssert(SymbolicReference("__INV__"))
target.body.add(assert)
}
@@ -255,19 +258,20 @@ class ProgMiterConstruction(val exec: PouExecutable) {
is EnumerationTypeDeclaration -> {
td.allowedValues.forEachIndexed { i, value ->
val vd = VariableDeclaration(
- "${td.name}__${value.text.toUpperCase()}",
+ "${td.name}__${value.text.uppercase()}",
VariableDeclaration.CONSTANT,
SimpleTypeDeclaration(INT, IntegerLit(i)))
target.scope.topLevel.add(vd)
}
- val fdecl = FunctionDeclaration("nondet_${td.name.toLowerCase()}",
+ val fdecl = FunctionDeclaration(
+ "nondet_${td.name.lowercase()}",
returnType = RefTo(INT))
fdecl.scope.add(VariableDeclaration("x", VariableDeclaration.LOCAL, INT))
fdecl.stBody = StatementList().also {
val x = SymbolicReference("x")
- val assume = td.values.map {
- x eq IntegerLit(INT, it.toBigInteger())
+ val assume = td.values.map { int ->
+ x eq IntegerLit(INT, int.toBigInteger())
}.disjunction()
it.add(SpecialCommentFactory.createHavoc("x", INT))
it.add(SpecialCommentFactory.createAssume(assume))
@@ -307,8 +311,8 @@ class ExpressionConversion(val enumValues: EnumValueTable) : SMVAstVisitor BooleanLit(l.value == true)
is SMVWordType -> IntegerLit(INT, l.value.toString().toBigInteger())
is EnumType -> {
- val et = enumValues[l.value.toString().toUpperCase()]
- ?: error("No enum defined which contains ${l.value}. Defined values: ${enumValues.keys}")
+ val et = enumValues[l.value.toString().uppercase(Locale.getDefault())]
+ ?: error("No enum defined which contains ${l.value}. Defined values: ${enumValues.keys}")
EnumLit(et, l.value.toString())
}
else -> error("Literals of type '${l.javaClass} are not supported")
@@ -391,7 +395,11 @@ class InvocationBasedProductProgramBuilder(name: String = "main") {
}
private fun createInstance(p: ReactiveProgram, fbd: FunctionBlockDeclaration): VariableDeclaration {
- val vd = VariableDeclaration(p.name.toLowerCase(), VariableDeclaration.LOCAL, FunctionBlockDataType(fbd))
+ val vd = VariableDeclaration(
+ p.name.lowercase(Locale.getDefault()),
+ VariableDeclaration.LOCAL,
+ FunctionBlockDataType(fbd)
+ )
target.scope.add(vd)
return vd
diff --git a/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/exception/SpecificationInterfaceMisMatchException.kt b/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/exception/SpecificationInterfaceMisMatchException.kt
index 54cf5980e..495133ddc 100644
--- a/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/exception/SpecificationInterfaceMisMatchException.kt
+++ b/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/exception/SpecificationInterfaceMisMatchException.kt
@@ -68,7 +68,7 @@ class SpecificationInterfaceMisMatchException : GetetaException {
var computed: MutableMap = HashMap()
init {
- this.reference = name.toLowerCase()
+ this.reference = name.lowercase(Locale.getDefault())
}
@@ -79,8 +79,13 @@ class SpecificationInterfaceMisMatchException : GetetaException {
}
private fun getLevenstheinToRef(o1: String): Int {
- val k = o1.toLowerCase()
- return (computed as java.util.Map).computeIfAbsent(k) { s -> levenshteinDistance(reference, s) }
+ val k = o1.lowercase(Locale.getDefault())
+ return (computed as java.util.Map).computeIfAbsent(k) { s ->
+ levenshteinDistance(
+ reference,
+ s
+ )
+ }
}
/**
diff --git a/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/io/TblLanguageToSmv.kt b/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/io/TblLanguageToSmv.kt
index 1080de794..22d9b7b65 100644
--- a/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/io/TblLanguageToSmv.kt
+++ b/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/io/TblLanguageToSmv.kt
@@ -194,7 +194,7 @@ class TblLanguageToSmv(private val columnVariable: SVariable,
if (isReference)
throw IllegalExpressionException("You referenced a variable $varText, " +
"but it is not found as a defined program variable.")
- SEnumLiteral(varText.toUpperCase())
+ SEnumLiteral(varText.uppercase(Locale.getDefault()))
}
}
diff --git a/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/model/GeneralizedTestTable.kt b/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/model/GeneralizedTestTable.kt
index 14d6ecf1e..22f9ed229 100644
--- a/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/model/GeneralizedTestTable.kt
+++ b/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/model/GeneralizedTestTable.kt
@@ -52,13 +52,13 @@ abstract class ColumnVariable(open var category: ColumnCategory = ColumnCategory
}
data class ProgramVariable(
- override var name: String,
- override var dataType: AnyDt,
- override var logicType: SMVType,
- override var category: ColumnCategory = ColumnCategory.ASSUME,
- var isState: Boolean = false,
- var isNext: Boolean = false,
- var programRun: Int = 0) : ColumnVariable(category) {
+ override var name: String,
+ override var dataType: AnyDt,
+ override var logicType: SMVType,
+ override var category: ColumnCategory = ColumnCategory.ASSUME,
+ var isState: Boolean = false,
+ var isNext: Boolean = false,
+ var programRun: Int = 0) : ColumnVariable(category) {
override val humanCategory: String
get() {
@@ -83,7 +83,7 @@ data class ProgramVariable(
*
*/
override fun externalVariable(programRunNames: List, tableName: String) =
- SVariable("${programRunNames[programRun]}.$realName", logicType)
+ SVariable("${programRunNames[programRun]}.$realName", logicType)
/**
*
@@ -92,18 +92,18 @@ data class ProgramVariable(
}
data class ConstraintVariable(
- override var name: String,
- override var dataType: AnyDt,
- override var logicType: SMVType,
- var constraint: TestTableLanguageParser.CellContext? = null)
+ override var name: String,
+ override var dataType: AnyDt,
+ override var logicType: SMVType,
+ var constraint: TestTableLanguageParser.CellContext? = null)
: Variable()
data class ProjectionVariable(
- override var name: String,
- override var dataType: AnyDt,
- override var logicType: SMVType,
- override var category: ColumnCategory = ColumnCategory.ASSUME,
- var constraint: MutableList = arrayListOf())
+ override var name: String,
+ override var dataType: AnyDt,
+ override var logicType: SMVType,
+ override var category: ColumnCategory = ColumnCategory.ASSUME,
+ var constraint: MutableList = arrayListOf())
: ColumnVariable(category) {
val arity: Int
@@ -121,7 +121,7 @@ data class ProjectionVariable(
*
*/
override fun externalVariable(programRunNames: List, tableName: String) =
- SVariable("$tableName.$name", logicType)
+ SVariable("$tableName.$name", logicType)
/**
*
@@ -139,28 +139,28 @@ data class SmvFunctionDefinition(val body: SMVExpr, val parameter: List = listOf(),
- val vars: MutableMap = hashMapOf(),
- val refs: MutableMap = hashMapOf(),
- val functions: MutableMap = hashMapOf(),
- val fillers: MutableMap = hashMapOf()) {
+ val relational: Boolean = false,
+ val programRuns: List = listOf(),
+ val vars: MutableMap = hashMapOf(),
+ val refs: MutableMap = hashMapOf(),
+ val functions: MutableMap = hashMapOf(),
+ val fillers: MutableMap = hashMapOf()) {
fun isVariable(v: String) = v in this
fun getSMVVariable(v: Variable) =
- vars.computeIfAbsent(v) { v.internalVariable(programRuns) }
+ vars.computeIfAbsent(v) { v.internalVariable(programRuns) }
fun getReference(variable: SVariable, cycles: Int): SVariable =
- when {
- cycles == 0 -> variable
- cycles > 0 -> throw IllegalArgumentException("no future references are allowed.")
- else -> {
- val newName = GetetaFacade.getHistoryName(variable, abs(cycles))
- val ref = SVariable(newName, variable.dataType!!)
- refs[variable] = min(refs.getOrDefault(variable, cycles), cycles)
- ref
- }
+ when {
+ cycles == 0 -> variable
+ cycles > 0 -> throw IllegalArgumentException("no future references are allowed.")
+ else -> {
+ val newName = GetetaFacade.getHistoryName(variable, abs(cycles))
+ val ref = SVariable(newName, variable.dataType!!)
+ refs[variable] = min(refs.getOrDefault(variable, cycles), cycles)
+ ref
}
+ }
operator fun contains(varText: String) = vars.keys.any { it.name == varText }
@@ -172,11 +172,11 @@ class ParseContext(
val va = if (programRun != null)
vars.keys.find { it.name == v && (it as? ProgramVariable)?.programRun == programRun }
- ?: throw IllegalArgumentException("Could not find a variable for $programRun|>$v in signature. " +
- "Signature is ${vars.keys.joinToString { it.name }}")
+ ?: throw IllegalArgumentException("Could not find a variable for $programRun|>$v in signature. " +
+ "Signature is ${vars.keys.joinToString { it.name }}")
else
vars.keys.find { it.name == v }
- ?: throw IllegalArgumentException("Could not find a variable for $v in signature.")
+ ?: throw IllegalArgumentException("Could not find a variable for $v in signature.")
return getSMVVariable(va)
}
@@ -194,13 +194,13 @@ class ParseContext(
}
class GeneralizedTestTable(
- var name: String = "anonym",
- val programVariables: MutableList = ArrayList(),
- val constraintVariables: MutableList = ArrayList(),
- var properties: MutableMap = HashMap(),
- var region: Region = Region(0),
- val functions: LookupList = ArrayLookupList(),
- var programRuns: List = arrayListOf()
+ var name: String = "anonym",
+ val programVariables: MutableList = ArrayList(),
+ val constraintVariables: MutableList = ArrayList(),
+ var properties: MutableMap = HashMap(),
+ var region: Region = Region(0),
+ val functions: LookupList = ArrayLookupList(),
+ var programRuns: List = arrayListOf()
) {
val options: TableOptions by lazy {
TableOptions(properties)
@@ -277,8 +277,8 @@ class GeneralizedTestTable(
}
val maxProgramRun: Int
get() = programVariables
- .filterIsInstance(ProgramVariable::class.java)
- .map { it.programRun }.maxBy { it } ?: 0
+ .filterIsInstance(ProgramVariable::class.java)
+ .map { it.programRun }.maxBy { it } ?: 0
fun getProgramVariables(name: String, run: Int?): ColumnVariable {
val pv = programVariables.find { it.respondTo(name, run) }
@@ -410,18 +410,18 @@ sealed class Duration {
fun Duration.repr(): String =
- when (this) {
- is Duration.ClosedInterval -> "[$lower, $upper]"
- Duration.Omega -> "omega"
- is Duration.OpenInterval -> ">=$lower"
- }
+ when (this) {
+ is Duration.ClosedInterval -> "[$lower, $upper]"
+ Duration.Omega -> "omega"
+ is Duration.OpenInterval -> ">=$lower"
+ }
fun Duration.isOptional(time: Int): Boolean =
- when (this) {
- is Duration.ClosedInterval -> lower <= time
- Duration.Omega -> false
- is Duration.OpenInterval -> lower <= time
- }
+ when (this) {
+ is Duration.ClosedInterval -> lower <= time
+ Duration.Omega -> false
+ is Duration.OpenInterval -> lower <= time
+ }
sealed class TableNode(open var id: String, var duration: Duration = Duration.ClosedInterval(1, 1)) {
@@ -449,9 +449,9 @@ data class Region(override var id: String,
}
data class GotoTransition(
- var tableName: String,
- var rowId: String,
- var kind: Kind = Kind.PASS
+ var tableName: String,
+ var rowId: String,
+ var kind: Kind = Kind.PASS
) {
enum class Kind { PASS, MISS, FAIL }
}
@@ -498,15 +498,15 @@ data class TableRow(override var id: String) : TableNode(id) {
*/
val pauseProgramRuns: List
get() = controlCommands.filterIsInstance()
- .map { it.affectedProgramRun }
+ .map { it.affectedProgramRun }
val backwardProgramRuns: List
get() = controlCommands.filterIsInstance()
- .map { it.affectedProgramRun }
+ .map { it.affectedProgramRun }
val backwardTargetedRows: List
get() = controlCommands.filterIsInstance()
- .map { it.jumpToRow }
+ .map { it.jumpToRow }
/*override val automataStates: MutableList = ArrayList()
@@ -610,12 +610,12 @@ fun TableRow.getUsedGlobalVariables(gtt: GeneralizedTestTable): List>
get() {
val m =
- programRuns.mapIndexed { index, _ -> index to TreeSet() }
- .toMap()
+ programRuns.mapIndexed { index, _ -> index to TreeSet() }
+ .toMap()
region.flat().flatMap { it.controlCommands }
- .filterIsInstance()
- .forEach {
- m[it.affectedProgramRun]!!.add(it.jumpToRow)
- }
+ .filterIsInstance()
+ .forEach {
+ m[it.affectedProgramRun]!!.add(it.jumpToRow)
+ }
return m
}
diff --git a/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/monitor/cmonitor.kt b/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/monitor/cmonitor.kt
index 125ba8b69..c18039856 100644
--- a/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/monitor/cmonitor.kt
+++ b/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/monitor/cmonitor.kt
@@ -34,8 +34,8 @@ private class CMonitorGeneratorImpl(val gtt: GeneralizedTestTable, val automaton
val monitor = Monitor()
val stream = StringWriter()
val writer = CodeWriter(stream)
- val state_t = "state_${gtt.name.toLowerCase()}_t"
- val inout_t = "inout_${gtt.name.toLowerCase()}_t"
+ val state_t = "state_${gtt.name.lowercase(Locale.getDefault())}_t"
+ val inout_t = "inout_${gtt.name.lowercase(Locale.getDefault())}_t"
val userReset = "FORCE_RST"
val error = "ERROR"
diff --git a/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/monitor/cppmonitor.kt b/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/monitor/cppmonitor.kt
index 4266613a3..71c6aff5a 100644
--- a/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/monitor/cppmonitor.kt
+++ b/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/monitor/cppmonitor.kt
@@ -19,6 +19,7 @@ import edu.kit.iti.formal.util.CodeWriter
import edu.kit.iti.formal.util.error
import edu.kit.iti.formal.util.joinInto
import edu.kit.iti.formal.util.warn
+import java.util.*
val EMPTY_COLUMN = SVariable("ERROR", SMVTypes.BOOLEAN)
@@ -435,7 +436,7 @@ class CppCombinedMonitorGenerationImpl(
}
private val Monitor.instanceName: String
- get() = "_" + this.name.toLowerCase()
+ get() = "_" + this.name.lowercase(Locale.getDefault())
}
private fun CodeWriter.historyValuesDeclaration(gtt: GeneralizedTestTable) {
diff --git a/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/print/text.kt b/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/print/text.kt
index 46565d59b..bf538d259 100644
--- a/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/print/text.kt
+++ b/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/print/text.kt
@@ -249,7 +249,7 @@ class GridPrinter(
val cells = grid.map { it[c] }
val width = cells.asSequence()
.map { options.spacePadding * 2 + if (it.width < 0) it.content.length else it.width }
- .max() ?: options.columnMinWidth
+ .maxOrNull() ?: options.columnMinWidth
cells.forEach { it.width = Math.max(options.columnMinWidth, width) }
}
}
diff --git a/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/viz/ods.kt b/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/viz/ods.kt
index faa2ed99a..948294aef 100644
--- a/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/viz/ods.kt
+++ b/geteta/src/main/kotlin/edu/kit/iti/formal/automation/testtables/viz/ods.kt
@@ -469,7 +469,7 @@ class ODSDebugTable(
unwinding.size * 2, categories.size * 2)
var currentRow = 1
val headerRows: Int
- get() = (categories.minBy { it.group.size })?.group?.size ?: 0
+ get() = (categories.minByOrNull { it.group.size })?.group?.size ?: 0
override fun run() {
writeHeader()
diff --git a/geteta/src/test/kotlin/edu/kit/iti/formal/automation/testtables/viz/AutomataDrawerTest.kt b/geteta/src/test/kotlin/edu/kit/iti/formal/automation/testtables/viz/AutomataDrawerTest.kt
index 351d03fc2..d6a1b06d2 100644
--- a/geteta/src/test/kotlin/edu/kit/iti/formal/automation/testtables/viz/AutomataDrawerTest.kt
+++ b/geteta/src/test/kotlin/edu/kit/iti/formal/automation/testtables/viz/AutomataDrawerTest.kt
@@ -12,7 +12,7 @@ import java.io.File
class AutomataDrawerTest {
@Test
fun testSimple() =
- renderAndShow("examples/NewFile.tt.txt")
+ renderAndShow("examples/NewFile.gtt")
@Test
fun testMinMax() = renderAndShow("examples/MinMax/MinMax.tt.txt")
diff --git a/ide/build.gradle b/ide/build.gradle
index 135736f45..b1f218804 100644
--- a/ide/build.gradle
+++ b/ide/build.gradle
@@ -1,15 +1,16 @@
plugins {
id("application")
+ id 'org.openjfx.javafxplugin' version '0.0.10'
}
-/*
+
javafx {
- version = "13"
- modules = [ 'javafx.controls' ]
-}*/
+ version = "21"
+ modules = ["javafx.controls", "javafx.controls", "javafx.fxml", "javafx.graphics"]
+}
-mainClassName = "edu.kit.iti.formal.automation.ide.Ide"
-//mainClassName = "edu.kit.iti.formal.automation.idefx.IdeFx"
+//mainClassName = "edu.kit.iti.formal.automation.ide.Ide"
+mainClassName = "edu.kit.iti.formal.automation.fx.FxKt"
dependencies {
implementation project(':symbex')
implementation project(':geteta')
@@ -18,28 +19,19 @@ dependencies {
implementation 'com.github.ajalt.clikt:clikt:4.2.1'
- implementation group: 'com.fifesoft', name: 'autocomplete', version: '3.3.1'
- //compile group: 'org.javassist', name: 'javassist', version: '3.27.0-GA'
- //compile 'me.tomassetti.antlr4c3:antlr4-c3-kotlin:0.1.0'
- implementation group: 'com.fifesoft', name: 'rsyntaxtextarea', version: '3.3.4'
- implementation group: 'com.fifesoft', name: 'rstaui', version: '3.3.1'
- implementation group: 'com.fifesoft', name: 'spellchecker', version: '3.3.1'
-
- //compile group: 'de.sciss', name: 'weblaf', version: '2.1.4'
- implementation 'io.github.vincenzopalazzo:material-ui-swing:1.1.4'
-
- //compile group: 'org.xhtmlrenderer', name: 'flying-saucer-core', version: '9.1.18'
-
- implementation group: 'com.miglayout', name: 'miglayout-swing', version: '11.2'
- implementation files("lib/docking-frames-common.jar", "lib/docking-frames-core.jar",
- "lib/docking-frames-ext-toolbar.jar", "lib/docking-frames-ext-toolbar-common.jar")
+ implementation("no.tornado:tornadofx:1.7.20")
+ implementation group: 'com.miglayout', name: 'miglayout-javafx', version: '5.2'
+ implementation group: 'org.fxmisc.richtext', name: 'richtextfx', version: '0.10.5'
+ implementation 'org.kordamp.ikonli:ikonli-fontawesome5-pack:12.0.0'
+ implementation 'org.kordamp.ikonli:ikonli-javafx:12.0.0'
- implementation group: 'org.netbeans.api', name: 'org-netbeans-swing-outline', version: 'RELEASE731'
+ implementation 'org.jfxtras:jmetro:11.6.15'
+ implementation 'com.pixelduke:fxribbon:1.2.2'
}
repositories {
maven {
- url = "https://bits.netbeans.org/maven2/"
+ url 'https://oss.sonatype.org/content/repositories/snapshots/'
}
}
diff --git a/ide/lib/docking-frames-common.jar b/ide/lib/docking-frames-common.jar
deleted file mode 100644
index a7fb91207..000000000
Binary files a/ide/lib/docking-frames-common.jar and /dev/null differ
diff --git a/ide/lib/docking-frames-core.jar b/ide/lib/docking-frames-core.jar
deleted file mode 100644
index 6342f7746..000000000
Binary files a/ide/lib/docking-frames-core.jar and /dev/null differ
diff --git a/ide/lib/docking-frames-ext-toolbar-common.jar b/ide/lib/docking-frames-ext-toolbar-common.jar
deleted file mode 100644
index adb07bf46..000000000
Binary files a/ide/lib/docking-frames-ext-toolbar-common.jar and /dev/null differ
diff --git a/ide/lib/docking-frames-ext-toolbar.jar b/ide/lib/docking-frames-ext-toolbar.jar
deleted file mode 100644
index f97be278c..000000000
Binary files a/ide/lib/docking-frames-ext-toolbar.jar and /dev/null differ
diff --git a/ide/src/main/kotlin/edu/kit/iti/formal/automation/fx/editor.kt b/ide/src/main/kotlin/edu/kit/iti/formal/automation/fx/editor.kt
new file mode 100644
index 000000000..81d1bb32e
--- /dev/null
+++ b/ide/src/main/kotlin/edu/kit/iti/formal/automation/fx/editor.kt
@@ -0,0 +1,381 @@
+package edu.kit.iti.formal.automation.fx
+
+import edu.kit.iti.formal.automation.IEC61131Facade
+import edu.kit.iti.formal.automation.analysis.ReportCategory
+import edu.kit.iti.formal.automation.analysis.ReportLevel
+import edu.kit.iti.formal.automation.parser.IEC61131Lexer
+import edu.kit.iti.formal.automation.parser.IEC61131Lexer.*
+import edu.kit.iti.formal.automation.st.ast.Position
+import edu.kit.iti.formal.automation.testtables.GetetaFacade
+import edu.kit.iti.formal.automation.testtables.grammar.TestTableLanguageLexer
+import edu.kit.iti.formal.smt.SmtLibv2Lexer
+import edu.kit.iti.formal.smv.parser.SMVLexer
+import javafx.beans.InvalidationListener
+import javafx.beans.binding.Bindings
+import javafx.beans.property.SimpleBooleanProperty
+import javafx.beans.property.SimpleListProperty
+import javafx.beans.property.SimpleObjectProperty
+import javafx.collections.FXCollections
+import javafx.stage.Popup
+import org.antlr.v4.runtime.CharStream
+import org.antlr.v4.runtime.CharStreams
+import org.antlr.v4.runtime.Lexer
+import org.antlr.v4.runtime.Token
+import org.fxmisc.richtext.CodeArea
+import org.fxmisc.richtext.LineNumberFactory
+import org.fxmisc.richtext.event.MouseOverTextEvent
+import org.fxmisc.richtext.model.StyleSpans
+import org.fxmisc.richtext.model.StyleSpansBuilder
+import org.reactfx.EventStreams
+import tornadofx.*
+import tornadofx.EventBus.RunOn.ApplicationThread
+import java.io.File
+import java.time.Duration
+import java.util.*
+
+
+object NewIssues : FXEvent(ApplicationThread)
+
+
+object Editors {
+ fun getLanguageForFilename(file: File) = getEditorForSuffix(file.extension)
+ fun getEditorForSuffix(suffix: String): Language? =
+ when (suffix) {
+ "tt", "gtt" -> TTLanguage
+ "st", "iec" -> StLanguage
+ "smv" -> SmvLanguage
+ "smt" -> SmtLanguage
+ else -> null
+ }
+}
+
+
+open class Editor : View() {
+ final override val root = CodeArea("")
+ val dirtyProperty = SimpleBooleanProperty(this, "dirty", false)
+ val dirty by dirtyProperty
+ val filenameProperty = SimpleObjectProperty(this, "filename", null)
+ val filename by filenameProperty
+ val languageProperty = SimpleObjectProperty(this, "language", null)
+ val language by languageProperty
+ val issuesProperty = SimpleListProperty(this, "issues", FXCollections.observableArrayList())
+ val issues by issuesProperty
+
+ val editorTitle = Bindings.createStringBinding(
+ { -> (filenameProperty.value?.name ?: "unknown") + (if (dirtyProperty.value) "*" else "") },
+ dirtyProperty,
+ filenameProperty
+ )
+
+
+ init {
+ root.paragraphGraphicFactory = LineNumberFactory.get(root)
+ root.isLineHighlighterOn = true
+
+ EventStreams.changesOf(root.textProperty())
+ .subscribe {
+ languageProperty.value?.also {
+ reHighlight()
+ }
+ }
+
+ EventStreams.changesOf(root.textProperty())
+ .forgetful()
+ .successionEnds(Duration.ofMillis(500))
+ .subscribe { runLinter() }
+
+ issuesProperty.addListener(InvalidationListener { _ -> reHighlight() })
+
+ filenameProperty.addListener { _, _, new ->
+ languageProperty.value = Editors.getLanguageForFilename(new)
+ }
+
+ languageProperty.addListener { _, _, new ->
+ new?.also {
+ if (root.text.isNotEmpty()) {
+ reHighlight()
+ }
+ }
+ }
+
+ root.mouseOverTextDelay = Duration.ofMillis(200)
+ val popup = Popup()
+ root.addEventHandler(MouseOverTextEvent.MOUSE_OVER_TEXT_BEGIN) { e ->
+ val chIdx = e.characterIndex
+ issues.find { it.startOffset <= chIdx && chIdx <= it.endOffset }?.let { issue ->
+ val popupMsg = label(issue.message) {
+ style {
+ backgroundColor += c("black")
+ fill = c("white")
+ paddingAll = 5
+ }
+ }
+ popup.content.add(popupMsg)
+ val pos = e.screenPosition
+ popup.show(currentWindow, pos.x, pos.y + 10)
+ }
+ }
+ root.addEventHandler(MouseOverTextEvent.MOUSE_OVER_TEXT_END) { e -> popup.hide() }
+ }
+
+ private fun runLinter() {
+ val text = root.text
+ language?.parseFile(CharStreams.fromString(text))?.let {
+ issues.setAll(it)
+ }
+ }
+
+ private fun reHighlight() {
+ language?.let {
+ try {
+ root.setStyleSpans(0, computeHighlighting(it))
+ } catch (e: Exception) {/*ignore*/
+ }
+
+ try {
+ issues.forEach {
+ root.setStyle(
+ it.startOffset, it.endOffset + 1,
+ Collections.singleton("error")
+ )
+ }
+ } catch (e: Exception) {/*ignore*/
+ }
+ }
+ }
+
+
+ fun computeHighlighting(language: Language): StyleSpans>? {
+ val text = root.text
+ val spansBuilder = StyleSpansBuilder>()
+ val lexer = language.lexerFactory(CharStreams.fromString(text))
+ do {
+ val tok = lexer.nextToken()
+ if (tok.type == -1) break
+ val typ = language.getStyleClass(tok.type)// lexer.vocabulary.getSymbolicName(tok.type)
+ spansBuilder.add(Collections.singleton(typ), tok.text.length)
+ } while (tok.type != -1)
+ return spansBuilder.create()
+ }
+}
+
+abstract class Language {
+ abstract val name: String
+ abstract fun lexerFactory(input: CharStream): Lexer
+
+ protected var structural: Set = setOf()
+ protected var separators: Set = setOf()
+ protected var literals: Set = setOf()
+ protected var identifiers: Set = setOf()
+ protected var specialIds: Set = setOf()
+ protected var comments: Set = setOf()
+ protected var datatype: Set = setOf()
+ protected var control: Set = setOf()
+ protected var operators: Set = setOf()
+ protected var errorChar: Int = -2
+
+ fun getStyleClass(tokenType: Int) =
+ when (tokenType) {
+ in separators -> "separator"
+ in structural -> "structural"
+ in literals -> "literal"
+ in identifiers -> "identifier"
+ in specialIds -> "fancy-identifier"
+ in comments -> "comment"
+ in datatype -> "datatype"
+ in control -> "control"
+ in operators -> "operators"
+ else -> {
+ System.err.println("token type $tokenType (${javaClass.name}) is not registered for syntax highlightning.")
+ ""
+ }
+ }
+
+ abstract fun parseFile(fromString: CharStream): List?
+}
+
+object StLanguage : Language() {
+ override val name: String = "StructuredText"
+
+ override fun lexerFactory(input: CharStream): Lexer = IEC61131Lexer(input)
+ override fun parseFile(fromString: CharStream): List {
+ val (_, errors) = IEC61131Facade.fileResolve(fromString, true)
+ return errors
+ }
+
+ private fun MutableSet.addAll(vararg items: Int) {
+ items.forEach { add(it) }
+ }
+
+ init {
+ structural = setOf(
+ PROGRAM, INITIAL_STEP, TRANSITION,
+ END_TRANSITION, END_VAR, VAR,
+ VAR_ACCESS, VAR_CONFIG, VAR_EXTERNAL,
+ VAR_GLOBAL,
+ VAR_INPUT,
+ VAR_IN_OUT,
+ VAR_OUTPUT,
+ VAR_TEMP,
+ END_PROGRAM,
+ END_ACTION,
+ END_CASE,
+ END_CLASS,
+ END_CONFIGURATION,
+ END_FUNCTION_BLOCK,
+ FUNCTION_BLOCK,
+ FUNCTION,
+ END_FUNCTION,
+ END_INTERFACE,
+ END_METHOD,
+ INTERFACE,
+ METHOD,
+ END_NAMESPACE,
+ NAMESPACE,
+ END_STEP,
+ STEP,
+ TYPE,
+ END_TYPE,
+ STRUCT, END_STRUCT,
+ CONFIGURATION, END_CONFIGURATION,
+ ACTION, END_ACTION
+ )
+
+ setOf(
+ ANY_BIT,
+ ARRAY,
+ STRING,
+ WSTRING,
+ ANY_DATE,
+ ANY_INT,
+ ANY_NUM,
+ ANY_REAL,
+ REAL,
+ LREAL,
+ INT,
+ DINT,
+ UDINT,
+ SINT,
+ USINT,
+ ULINT,
+ DINT,
+ LINT,
+ DATE,
+ DATE_AND_TIME,
+ TIME,
+ WORD,
+ LWORD,
+ DWORD,
+ BOOL
+ )
+
+ literals = setOf(
+ DATE_LITERAL,
+ INTEGER_LITERAL,
+ BITS_LITERAL,
+ CAST_LITERAL,
+ DIRECT_VARIABLE_LITERAL,
+ REAL_LITERAL,
+ STRING_LITERAL,
+ TOD_LITERAL,
+ TIME_LITERAL,
+ WSTRING_LITERAL
+ )
+
+ control = setOf(
+ IF, ELSE, ELSEIF, FOR, END_FOR,
+ WHILE, END_WHILE, REPEAT, END_REPEAT,
+ END_IF, DO, THEN, UNTIL, TO,
+ WITH, CASE, END_CASE, OF
+ )
+
+ operators = setOf(
+ NOT, AND, OR, MOD, DIV, MULT, MINUS, EQUALS, NOT_EQUALS,
+ GREATER_EQUALS, GREATER_THAN, LESS_EQUALS, LESS_THAN,
+ IL_ADD, IL_ANDN, IL_CAL, IL_CALC, IL_CALCN, IL_CD, IL_CLK,
+ IL_CU, IL_DIV, IL_EQ, IL_GE, IL_GT, IL_IN, IL_JMP, IL_JMPC, IL_JMPCN, IL_LD, IL_LDN, IL_LE, IL_LT,
+ IL_MOD, IL_MUL, IL_NE, IL_NOT, IL_ORN, IL_PT, IL_PV, IL_R1, IL_R, IL_RET, IL_RETC, IL_RETCN,
+ IL_S1, IL_S, IL_ST, IL_STN, IL_STQ, IL_SUB, IL_XORN, IL_OR
+ )
+
+ identifiers = setOf(IDENTIFIER)
+ comments = setOf(LINE_COMMENT, COMMENT)
+ errorChar = ERROR_CHAR
+ }
+}
+
+object TTLanguage : Language() {
+ override val name: String = "TestTables"
+
+ override fun lexerFactory(input: CharStream): Lexer = TestTableLanguageLexer(input)
+ override fun parseFile(fromString: CharStream): List {
+ val p = GetetaFacade.createParser(fromString)
+ p.file()
+ return p.errorReporter.errors.map {
+ val tok = it.offendingSymbol as Token
+ Problem(
+ tok.tokenSource.sourceName ?: "",
+ it.msg ?: "syntax error",
+ Position.start(tok),
+ Position.end(tok),
+ ReportCategory.SYNTAX,
+ ReportLevel.ERROR,
+ )
+ }
+
+ }
+
+ init {
+ structural = setOf(
+ TestTableLanguageLexer.OPTIONS,
+ TestTableLanguageLexer.TABLE,
+ TestTableLanguageLexer.FUNCTION,
+ TestTableLanguageLexer.OF,
+ TestTableLanguageLexer.WITH,
+ TestTableLanguageLexer.VAR,
+ TestTableLanguageLexer.GVAR,
+ TestTableLanguageLexer.AS,
+ TestTableLanguageLexer.IF,
+ TestTableLanguageLexer.FI,
+ TestTableLanguageLexer.GROUP,
+ TestTableLanguageLexer.ROW,
+ TestTableLanguageLexer.INPUT,
+ TestTableLanguageLexer.OUTPUT,
+ TestTableLanguageLexer.VAR,
+ TestTableLanguageLexer.BACKWARD,
+ TestTableLanguageLexer.PLAY,
+ TestTableLanguageLexer.PAUSE,
+ TestTableLanguageLexer.STATE,
+ TestTableLanguageLexer.RELATIONAL
+ )
+ separators = setOf(
+ TestTableLanguageLexer.RBRACE,
+ TestTableLanguageLexer.LBRACE,
+ TestTableLanguageLexer.RPAREN,
+ TestTableLanguageLexer.LPAREN,
+ TestTableLanguageLexer.RBRACKET,
+ TestTableLanguageLexer.LBRACKET,
+ TestTableLanguageLexer.COLON,
+ TestTableLanguageLexer.COMMA
+ )
+ literals = setOf(
+ TestTableLanguageLexer.INTEGER
+ )
+ identifiers = setOf(TestTableLanguageLexer.FQ_VARIABLE, TestTableLanguageLexer.IDENTIFIER)
+ comments = setOf(TestTableLanguageLexer.COMMENT, TestTableLanguageLexer.LINE_COMMENT)
+ }
+}
+
+object SmvLanguage : Language() {
+ override val name: String = "Symbolic Model Verifier"
+
+ override fun lexerFactory(input: CharStream): Lexer = SMVLexer(input)
+ override fun parseFile(fromString: CharStream): List? = null
+
+}
+
+object SmtLanguage : Language() {
+ override val name: String = "SMT"
+ override fun lexerFactory(input: CharStream): Lexer = SmtLibv2Lexer(input)
+ override fun parseFile(fromString: CharStream): List? = null
+}
\ No newline at end of file
diff --git a/ide/src/main/kotlin/edu/kit/iti/formal/automation/fx/fx.kt b/ide/src/main/kotlin/edu/kit/iti/formal/automation/fx/fx.kt
new file mode 100644
index 000000000..f5bb1fcb4
--- /dev/null
+++ b/ide/src/main/kotlin/edu/kit/iti/formal/automation/fx/fx.kt
@@ -0,0 +1,370 @@
+package edu.kit.iti.formal.automation.fx
+
+import edu.kit.iti.formal.util.info
+import javafx.beans.property.SimpleObjectProperty
+import javafx.collections.FXCollections
+import javafx.event.EventHandler
+import javafx.geometry.Side
+import javafx.scene.Node
+import javafx.scene.control.Menu
+import javafx.scene.control.MenuItem
+import javafx.scene.control.Tab
+import javafx.scene.control.TabPane
+import javafx.scene.input.KeyCombination
+import javafx.scene.paint.Color
+import javafx.scene.text.FontWeight
+import javafx.stage.FileChooser
+import javafx.stage.Stage
+import jfxtras.styles.jmetro.JMetro
+import jfxtras.styles.jmetro.Style
+import org.kordamp.ikonli.javafx.FontIcon
+import org.kordamp.ikonli.javafx.IkonResolver
+import tornadofx.*
+import java.io.File
+import java.nio.file.Files
+import java.nio.file.Paths
+
+
+fun main(args: Array) {
+ launch(*args)
+}
+
+class IdeStyle : Stylesheet() {
+ companion object {
+ val styleTextArea by cssclass("styled-text-area")
+ val text by cssclass()
+ val errorChar by cssclass("error-char")
+ val structural by cssclass()
+ val literal by cssclass()
+ val identifier by cssclass()
+ val fancyIdentifier by cssclass("fancy-identifier")
+ val comment by cssclass()
+ val datatype by cssclass()
+ val control by cssclass()
+ val operators by cssclass()
+ }
+
+ init {
+ val base03 = Color.web("#002b36")
+ val base02 = Color.web("#073642")
+ val base01 = Color.web("#586e75")
+ val base00 = Color.web("#657b83")
+ val base0 = Color.web("#839496")
+ val base1 = Color.web("#93a1a1")
+ val base2 = Color.web("#eee8d5")
+ val base3 = Color.web("#fdf6e3")
+ val yellow = Color.web("#b58900")
+ val orange = Color.web("#cb4b16")
+ val red = Color.web("#dc322f")
+ val magenta = Color.web("#d33682")
+ val violet = Color.web("#6c71c4")
+ val blue = Color.web("#268bd2")
+ val cyan = Color.web("#2aa198")
+ val green = Color.web("#859900")
+
+ styleTextArea {
+ text {
+ backgroundColor += base03
+ }
+ }
+
+ errorChar {
+ backgroundColor += red
+ }
+
+ error {
+ fontWeight = FontWeight.BOLD
+ backgroundColor += red
+ }
+
+ separator {
+ //fill =
+ }
+
+ structural {
+ fill = blue
+ fontWeight = FontWeight.BOLD
+ }
+
+ literal {
+ fill = violet
+ }
+
+ identifier {
+ //fill = c(" #b58900")
+ }
+
+ fancyIdentifier {
+ fill = magenta
+ fontWeight = FontWeight.BOLD
+ }
+
+ comment {
+ fill = base01
+ }
+
+ datatype {
+ fill = blue
+ }
+
+ control {
+ fill = blue
+ }
+
+ operators {
+ fill = orange
+ }
+ }
+}
+
+
+class IdeFx : App(IdeView::class, IdeStyle::class) {
+ init {
+ //reloadStylesheetsOnFocus()
+ //dumpStylesheets()
+
+ }
+
+ override fun start(stage: Stage) {
+ super.start(stage)
+ val jMetro = JMetro(Style.LIGHT)
+ jMetro.scene = stage.scene
+ }
+}
+
+object ConfigurationPaths {
+ val operationSystem by lazy {
+ val os = System.getProperty("os.name")
+ when {
+ os.contains("Mac") -> "mac"
+ os.contains("Windows") -> "win"
+ os.contains("Linux") -> "lin"
+ else -> ""
+ }
+ }
+
+ val applicationName = "verifaps-fx"
+
+ val configFolder by lazy {
+ val home = System.getProperty("user.home")
+ val p = when (operationSystem) {
+ "mac" -> Paths.get(home, "Library", "Application Support", applicationName)
+ "win" -> {
+ val version = System.getProperty("os.version")
+ Paths.get(System.getenv("APPDATA"), applicationName)
+ }
+ "lin" -> {
+ Paths.get(home, ".config", applicationName)
+ }
+ else -> Paths.get(applicationName)
+ }
+ Files.createDirectories(p)
+ info("Configuration folder: $p")
+ p
+ }
+
+ val appDataPath by lazy {
+ configFolder.resolve("config.properties")
+ }
+
+ val recentFiles by lazy {
+ configFolder.resolve("recentfiles")
+ }
+}
+
+class IdeView : View("VERIFAPS IDE") {
+ val recentFiles = FXCollections.observableArrayList().also { seq ->
+ config.jsonArray("recentFiles")
+ ?.map { File(it.toString()) }
+ ?.forEach { seq.add(it) }
+ }
+
+ val currentEditor = SimpleObjectProperty(this, "currentEditor", null)
+
+
+ //region controllers
+ val menu = IdeMenu(this)
+ val fileNavigator = FileNavigator(this)
+ val outline = FileOutline()
+ val issues = Issues()
+
+ val left = drawer(multiselect = true, floatingContent = false) {
+ item("Navigator", expanded = false, showHeader = true) {
+ this.add(outline.root)
+ }
+ item("Files", expanded = true, showHeader = true) {
+ this.add(fileNavigator.root)
+ }
+ }
+ val bottom = drawer(Side.BOTTOM, multiselect = false, floatingContent = false) {
+ item("Issues") { add(Issues::class) }
+ item("Table Preview") { add(TTPreview::class) }
+ }
+ val blubber = drawer(Side.RIGHT, multiselect = false, floatingContent = false) {
+ item("Geteta") { add(Geteta::class) }
+ item("Reteta") { add(Reteta::class) }
+ }
+ val center = splitpane()
+
+ override val root = borderpane {
+ top = menu.root
+ center = this@IdeView.center
+ left = this@IdeView.left
+ bottom = this@IdeView.bottom
+ right = this@IdeView.blubber
+ }
+ //endregion
+
+ val statusBar = label("")
+ val editorTabPanes = arrayListOf(createEditorTabPane())
+ val openEditors = arrayListOf()
+
+ init {
+ center.items.addAll(editorTabPanes)
+ //if (appData.lastNavigatorPath.value != null)
+ // fileNavigator.rootFile.value = Paths.get(appData.lastNavigatorPath.value)
+ subscribe { publishMessage(it.text, it.graphic) }
+ open(File("geteta/examples/NewFile.gtt").absoluteFile)
+ }
+
+ fun publishMessage(status: String, graphic: Node? = null) {
+ statusBar.text = status
+ statusBar.graphic = graphic
+ }
+
+ private fun createEditorTabPane(): TabPane {
+ return TabPane()
+ }
+
+ fun createCodeEditor() {
+ addEditorTab(Editor())
+ }
+
+ fun addEditorTab(editor: Editor) {
+ val tabPanel = editorTabPanes.first()
+ val tab = Tab(editor.editorTitle.value, editor.root)
+ tabPanel.tabs.add(tab)
+ editor.editorTitle.addListener { _, _, new -> tab.text = new }
+ openEditors.add(editor)
+ editor.root.focusedProperty().addListener { obs, _, new -> if (new) currentEditor.value = editor }
+ currentEditor.value = editor
+ editor.root.requestFocus()
+ }
+
+ fun saveAs(editor: Editor? = currentEditor.value) =
+ editor?.also {
+ val fileChooser = FileChooser()
+ fileChooser.showSaveDialog(currentWindow)?.let { new ->
+ editor.filenameProperty.value = new
+ save(editor)
+ }
+ }
+
+ fun save(editor: Editor? = currentEditor.value) {
+ editor?.also { editor ->
+ editor.filenameProperty.value?.also { filename ->
+ filename.writeText(editor.root.text)
+ }
+ }
+ }
+
+ fun open() {
+ val fc = FileChooser()
+ fc.showOpenDialog(currentWindow)?.let { file ->
+ open(file)
+ }
+ }
+
+
+ fun open(f: File) {
+ if (f !in recentFiles) {
+ recentFiles.add(f)
+ }
+ val editor = Editor()
+ editor.filenameProperty.value = f
+ editor.root.insertText(0, f.readText())
+ addEditorTab(editor)
+ }
+
+ fun editorToTheRight(editor: Editor? = currentEditor.value) {
+ if (editor == null) return
+ val tabPane = editorTabPanes.find { it.tabs.any { tab -> tab.content == editor.root } }
+ if (tabPane != null) {
+ val tabIndex = editorTabPanes.indexOf(tabPane)
+ if (tabPane == editorTabPanes.last()) {
+ TabPane().also { editorTabPanes.add(it); center.items.add(it) }
+ }
+ val target = editorTabPanes[tabIndex + 1]
+ val tab = tabPane.tabs.find { it.content == editor.root }!!
+ tabPane.tabs.remove(tab)
+ target.tabs.add(tab)
+ }
+ }
+
+ fun editorToTheLeft(editor: Editor? = currentEditor.value) {
+ val tabPane = editorTabPanes.find { it.tabs.any { it.content == editor } }
+ if (tabPane != null) {
+ val tabIndex = editorTabPanes.indexOf(tabPane)
+ if (tabPane == editorTabPanes.first()) {
+ TabPane().also { editorTabPanes.add(0, it) }
+ }
+ val target = editorTabPanes[tabIndex - 1]
+ val tab = tabPane.tabs.find { it.content == editor }!!
+ tabPane.tabs.remove(tab)
+ target.tabs.add(tab)
+ }
+ }
+}
+
+class StatusMessage(val text: String, val graphic: Node? = null) : FXEvent()
+
+class IdeMenu(val ide: IdeView) : View() {
+ lateinit var recentFiles: MenuItem
+
+ override val root = menubar {
+ menu("File") {
+ item("New", "ctrl-n", null, ide::createCodeEditor)
+ item("Open", "ctrl-o", "fas-folder-open", ide::open)
+ val recentFiles = item("Recent files")
+ separator()
+ item("Save", "ctrl-s", "far-save", ide::save)
+ item("Save As...", "ctrl-shift-s", "fas-save", ide::saveAs)
+ separator()
+ item("Close", null, null, ide::close)
+ }
+ menu("Edit") {}
+ menu("View") {
+ item("Larger texts", "ctrl-PLUS", "fas-folder-open") {}
+ item("Smaller texts", "ctrl-MINUS", "fas-folder-open") {}
+ separator()
+ item("Editor to Left", "ctrl-LEFT", null, ide::editorToTheLeft)
+ item("Editor to Right", "ctrl-RIGHT", null, ide::editorToTheRight)
+ }
+ menu("Tools") {
+ item("Translate SFC to ST", null, null) {
+ /*currentEditor?.also {
+ val file = File(
+ it.file?.parentFile, it.file?.nameWithoutExtension +
+ "_translated." + it.file?.extension
+ )
+ val elements = IEC61131Facade.file(CharStreams.fromString(it.text))
+ IEC61131Facade.translateSfcToSt(elements)
+ file.bufferedWriter().use {
+ IEC61131Facade.printTo(it, elements, true)
+ }
+ open(file)*/
+ }
+ }
+ }
+}
+
+fun Menu.item(name: String, key: String?, ikon: String? = null, event: () -> Unit) {
+ val icon = ikon?.let { ref ->
+ val resolver = IkonResolver.getInstance()
+ resolver.resolve(ref).resolve(ref)?.let { FontIcon(it) }
+ }
+ item(name, key?.let { KeyCombination.keyCombination(it) }, icon) {
+ onAction = EventHandler { _ -> event() }
+ }
+}
+
diff --git a/ide/src/main/kotlin/edu/kit/iti/formal/automation/fx/issueview.kt b/ide/src/main/kotlin/edu/kit/iti/formal/automation/fx/issueview.kt
new file mode 100644
index 000000000..10c050d14
--- /dev/null
+++ b/ide/src/main/kotlin/edu/kit/iti/formal/automation/fx/issueview.kt
@@ -0,0 +1,29 @@
+package edu.kit.iti.formal.automation.fx
+
+import edu.kit.iti.formal.automation.analysis.ReporterMessage
+import javafx.collections.FXCollections
+import tornadofx.View
+import tornadofx.column
+import tornadofx.tableview
+
+/**
+ *
+ * @author Alexander Weigl
+ * @version 1 (3/21/21)
+ */
+class Issues : View("Issues") {
+ val issues = FXCollections.observableArrayList()
+
+ override val root = tableview(issues) {
+ column("File", Problem::sourceName)
+ column("Message", Problem::message)
+ }
+}
+
+typealias Problem = ReporterMessage
+
+interface ProblemService {
+ fun clearProblems(identity: Any)
+ fun announceProblems(identity: Any, problems: Iterable)
+ fun registerListener(listener: () -> Unit)
+}
diff --git a/ide/src/main/kotlin/edu/kit/iti/formal/automation/fx/navigator.kt b/ide/src/main/kotlin/edu/kit/iti/formal/automation/fx/navigator.kt
new file mode 100644
index 000000000..9f81fd972
--- /dev/null
+++ b/ide/src/main/kotlin/edu/kit/iti/formal/automation/fx/navigator.kt
@@ -0,0 +1,255 @@
+package edu.kit.iti.formal.automation.fx
+
+import javafx.beans.property.SimpleObjectProperty
+import javafx.collections.FXCollections
+import javafx.collections.ObservableList
+import javafx.event.ActionEvent
+import javafx.event.EventHandler
+import javafx.scene.Node
+import javafx.scene.control.*
+import javafx.scene.control.cell.TextFieldTreeCell
+import javafx.scene.input.KeyCombination
+import javafx.scene.paint.Color.*
+import javafx.util.StringConverter
+import org.kordamp.ikonli.Ikon
+import org.kordamp.ikonli.Ikonli
+import org.kordamp.ikonli.fontawesome5.FontAwesomeSolid
+import org.kordamp.ikonli.javafx.FontIcon
+import org.kordamp.ikonli.javafx.IkonResolver
+import tornadofx.View
+import tornadofx.contextmenu
+import tornadofx.separator
+import java.awt.Color
+import java.awt.Desktop
+import java.io.IOException
+import java.nio.file.Files
+import java.nio.file.Path
+import java.nio.file.Paths
+import kotlin.io.path.extension
+import kotlin.io.path.isDirectory
+import kotlin.io.path.name
+import tornadofx.item as titem
+
+/**
+ *
+ * @author Alexander Weigl
+ * @version 1 (3/21/21)
+ */
+
+class FileNavigator(main: IdeView) : View("Navigator") {
+ val rootFile = SimpleObjectProperty(
+ this, "rootFile",
+ Paths.get(".").normalize().toAbsolutePath()
+ )
+ val treeFile = TreeView(SimpleFileTreeItem(rootFile.value))
+ override val root = treeFile
+
+ private fun markFolderUnderMouse(event: ActionEvent) {
+
+ }
+
+
+ val contextMenu: ContextMenu = contextmenu {
+ item("Open file", "ENTER", null) {
+ markFolderUnderMouse(it)
+ treeFile.selectionModel.selectedItem?.let {
+ main.open(it.value.toFile())
+ }
+ }
+
+ item("Open in explorer") {
+ markFolderUnderMouse(it)
+ (treeFile.selectionModel.selectedItem)?.let { file ->
+ try {
+ Desktop.getDesktop()?.browseFileDirectory(file.value.toFile())
+ } catch (e: UnsupportedOperationException) {
+ ProcessBuilder("explorer", "/select,${file.value}").start()
+ }
+ }
+ }
+ item("System open") {
+ markFolderUnderMouse(it)
+ (treeFile.selectionModel.selectedItem)?.let { file ->
+ try {
+ Desktop.getDesktop()?.open(file.value.toFile())
+ } catch (e: UnsupportedOperationException) {
+ ProcessBuilder("explorer", "/select,${file.value}").start()
+ }
+ }
+ }
+
+ separator()
+
+ item("tree-new-file") {
+ markFolderUnderMouse(it)
+ treeFile.selectionModel.selectedItem?.let { item ->
+ val path = item.value!!
+ val dialog = TextInputDialog()
+ dialog.contentText = "File name:"
+ val name = dialog.showAndWait()
+ name.ifPresent {
+ val newFile = path.resolve(it)
+ try {
+ Files.createFile(newFile)
+ main.open(newFile.toFile())
+ refresh()
+ } catch (e: IOException) {
+ val a = Alert(Alert.AlertType.ERROR)
+ a.contentText = e.message
+ a.show()
+ }
+ }
+ }
+ }
+ item("tree-new-directory") {
+ markFolderUnderMouse(it)
+ treeFile.selectionModel.selectedItem?.let { item ->
+ val path = item.value!!
+ val dialog = TextInputDialog()
+ dialog.contentText = "Folder name:"
+ val name = dialog.showAndWait()
+ name.ifPresent {
+ val newFile = path.resolve(it)
+ try {
+ Files.createDirectory(newFile)
+ main.open(newFile.toFile())
+ refresh()
+ } catch (e: IOException) {
+ val a = Alert(Alert.AlertType.ERROR)
+ a.contentText = e.message
+ a.show()
+ }
+ }
+ }
+ }
+ separator()
+
+
+ item("Refresh") {}
+
+ item("Expand Tree") {
+ markFolderUnderMouse(it)
+ }
+
+ separator()
+
+ item("Go up") {
+ markFolderUnderMouse(it)
+ treeFile.root.value?.let { file ->
+ treeFile.root = SimpleFileTreeItem(file.parent.toAbsolutePath())
+ treeFile.root.isExpanded = true
+ }
+ }
+ item("Go into") {
+ markFolderUnderMouse(it)
+ (treeFile.selectionModel.selectedItem)?.let { file ->
+ treeFile.root = SimpleFileTreeItem(file.value.toAbsolutePath())
+ treeFile.root.isExpanded = true
+ }
+ }
+
+ separator()
+
+ item("Rename file") { }
+ item("Delete file") {}
+
+ separator()
+ }
+
+ fun refresh(): Unit {
+
+ }
+
+ init {
+ treeFile.contextMenu = contextMenu
+ treeFile.isEditable = false
+ treeFile.isShowRoot = true
+ rootFile.addListener { _, _, new ->
+ treeFile.root = SimpleFileTreeItem(new)
+ }
+ treeFile.setCellFactory { tv ->
+ TextFieldTreeCell(object : StringConverter() {
+ override fun toString(obj: Path?): String = obj?.fileName.toString() ?: ""
+ override fun fromString(string: String?): Path = Paths.get(string)
+ })
+ }
+ treeFile.root.isExpanded = true
+ }
+}
+
+fun ContextMenu.item(name: String, key: String? = null, ikon: String? = null, event: (ActionEvent) -> Unit) {
+ val icon = ikon?.let { ref ->
+ val resolver = IkonResolver.getInstance()
+ resolver.resolve(ref).resolve(ref)?.let { FontIcon(it) }
+ }
+ titem(name, key?.let { KeyCombination.keyCombination(it) }, icon) {
+ onAction = EventHandler(event)
+ }
+}
+
+class SimpleFileTreeItem(f: Path) : TreeItem(f) {
+ private val pathComparator: Comparator> = java.util.Comparator.comparingInt?> {
+ if (Files.isDirectory(it.value)) 0 else 1
+ }.thenComparing { it -> it.value.name }
+
+ private var isFirstTimeChildren = true
+ private var isFirstTimeLeaf = true
+ private var isLeaf = false
+
+ init {
+ graphic = NavigationIconFinder.find(f)
+ }
+
+ override fun getChildren(): ObservableList> {
+ if (isFirstTimeChildren) {
+ isFirstTimeChildren = false
+ super.getChildren().setAll(buildChildren(this))
+ }
+ return super.getChildren()
+ }
+
+ override fun isLeaf(): Boolean {
+ if (isFirstTimeLeaf) {
+ isFirstTimeLeaf = false
+ val f = value as Path
+ isLeaf = Files.isRegularFile(f)
+ }
+ return isLeaf
+ }
+
+ private fun buildChildren(node: TreeItem): ObservableList> {
+ val f = node.value
+ if (f != null && Files.isDirectory(f)) {
+ val children: ObservableList> = FXCollections.observableArrayList()
+ Files.list(f).forEach {
+ children.add(SimpleFileTreeItem(it))
+ }
+ return children.sorted(pathComparator)
+ }
+ return FXCollections.emptyObservableList()
+ }
+}
+
+object NavigationIconFinder {
+ private val resolver = IkonResolver.getInstance()
+ private val DIRECTORY = FontAwesomeSolid.FOLDER
+ private val FILE = FontAwesomeSolid.FILE
+ private val FILE_CODE = FontAwesomeSolid.FILE_CODE
+
+ private fun get(ref: String): FontIcon? {
+ return resolver.resolve(ref).resolve(ref)?.let { FontIcon(it) }!!
+ }
+
+ fun find(p: Path): Node? {
+ if (p.isDirectory()) {
+ return FontIcon(DIRECTORY)
+ }
+
+ return when (p.extension) {
+ "gtt", "rtt", "st" -> FontIcon(FILE_CODE)
+ else -> FontIcon(FILE).also {
+ it.iconColor = LIGHTGREY
+ }
+ }
+ }
+}
diff --git a/ide/src/main/kotlin/edu/kit/iti/formal/automation/fx/outline.kt b/ide/src/main/kotlin/edu/kit/iti/formal/automation/fx/outline.kt
new file mode 100644
index 000000000..760cf25e5
--- /dev/null
+++ b/ide/src/main/kotlin/edu/kit/iti/formal/automation/fx/outline.kt
@@ -0,0 +1,16 @@
+package edu.kit.iti.formal.automation.fx
+
+import javafx.scene.Parent
+import javafx.scene.control.TreeView
+import tornadofx.View
+
+/**
+ *
+ * @author Alexander Weigl
+ * @version 1 (3/21/21)
+ */
+class FileOutline : View("Outline") {
+ val outlineTree = TreeView()
+ override val root: Parent
+ get() = outlineTree
+}
diff --git a/ide/src/main/kotlin/edu/kit/iti/formal/automation/fx/tool.kt b/ide/src/main/kotlin/edu/kit/iti/formal/automation/fx/tool.kt
new file mode 100644
index 000000000..3bfdd2cb2
--- /dev/null
+++ b/ide/src/main/kotlin/edu/kit/iti/formal/automation/fx/tool.kt
@@ -0,0 +1,27 @@
+package edu.kit.iti.formal.automation.fx
+
+import edu.kit.iti.formal.automation.testtables.model.TableNode
+import javafx.scene.control.TreeTableView
+import tornadofx.View
+import tornadofx.label
+
+/**
+ *
+ * @author Alexander Weigl
+ * @version 1 (3/21/21)
+ */
+class Geteta : View("Geteta") {
+ override val root = label("Test") { }
+}
+
+class Reteta : View("Reteta") {
+ override val root = label("Test") { }
+}
+
+
+class TTPreview : View("Preview") {
+ override val root = TreeTableView()
+ init {
+
+ }
+}
\ No newline at end of file
diff --git a/ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/JavaJMLTokenFactory.kt b/ide/src/main/old/ide/JavaJMLTokenFactory.kt
similarity index 100%
rename from ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/JavaJMLTokenFactory.kt
rename to ide/src/main/old/ide/JavaJMLTokenFactory.kt
diff --git a/ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/LanguageSupport.kt b/ide/src/main/old/ide/LanguageSupport.kt
similarity index 100%
rename from ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/LanguageSupport.kt
rename to ide/src/main/old/ide/LanguageSupport.kt
diff --git a/ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/editor.kt b/ide/src/main/old/ide/editor.kt
similarity index 100%
rename from ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/editor.kt
rename to ide/src/main/old/ide/editor.kt
diff --git a/ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/editors/gtt.kt b/ide/src/main/old/ide/editors/gtt.kt
similarity index 100%
rename from ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/editors/gtt.kt
rename to ide/src/main/old/ide/editors/gtt.kt
diff --git a/ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/editors/smv.kt b/ide/src/main/old/ide/editors/smv.kt
similarity index 100%
rename from ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/editors/smv.kt
rename to ide/src/main/old/ide/editors/smv.kt
diff --git a/ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/editors/st.kt b/ide/src/main/old/ide/editors/st.kt
similarity index 100%
rename from ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/editors/st.kt
rename to ide/src/main/old/ide/editors/st.kt
diff --git a/ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/icons.kt b/ide/src/main/old/ide/icons.kt
similarity index 100%
rename from ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/icons.kt
rename to ide/src/main/old/ide/icons.kt
diff --git a/ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/ide.kt b/ide/src/main/old/ide/ide.kt
similarity index 100%
rename from ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/ide.kt
rename to ide/src/main/old/ide/ide.kt
diff --git a/ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/problems.kt b/ide/src/main/old/ide/problems.kt
similarity index 100%
rename from ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/problems.kt
rename to ide/src/main/old/ide/problems.kt
diff --git a/ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/services.kt b/ide/src/main/old/ide/services.kt
similarity index 100%
rename from ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/services.kt
rename to ide/src/main/old/ide/services.kt
diff --git a/ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/services/config.kt b/ide/src/main/old/ide/services/config.kt
similarity index 100%
rename from ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/services/config.kt
rename to ide/src/main/old/ide/services/config.kt
diff --git a/ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/services/recentfiles.kt b/ide/src/main/old/ide/services/recentfiles.kt
similarity index 100%
rename from ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/services/recentfiles.kt
rename to ide/src/main/old/ide/services/recentfiles.kt
diff --git a/ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/tools.kt b/ide/src/main/old/ide/tools.kt
similarity index 100%
rename from ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/tools.kt
rename to ide/src/main/old/ide/tools.kt
diff --git a/ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/tools/navigator.kt b/ide/src/main/old/ide/tools/navigator.kt
similarity index 100%
rename from ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/tools/navigator.kt
rename to ide/src/main/old/ide/tools/navigator.kt
diff --git a/ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/tools/overview.kt b/ide/src/main/old/ide/tools/overview.kt
similarity index 100%
rename from ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/tools/overview.kt
rename to ide/src/main/old/ide/tools/overview.kt
diff --git a/ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/tools/ttpreview.kt b/ide/src/main/old/ide/tools/ttpreview.kt
similarity index 100%
rename from ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/tools/ttpreview.kt
rename to ide/src/main/old/ide/tools/ttpreview.kt
diff --git a/ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/utils.kt b/ide/src/main/old/ide/utils.kt
similarity index 100%
rename from ide/src/main/kotlin/edu/kit/iti/formal/automation/ide/utils.kt
rename to ide/src/main/old/ide/utils.kt
diff --git a/ide/src/main/resources/config.toml b/ide/src/main/resources/config.toml
new file mode 100644
index 000000000..441bf9878
--- /dev/null
+++ b/ide/src/main/resources/config.toml
@@ -0,0 +1,74 @@
+[actions]
+[actions.save]
+name = "Save"
+accel = "Ctrl+s"
+icon = "far-save"
+[actions.save-as]
+name = "Save As"
+accel = "Ctrl+Shift+s"
+icon = "fas-save"
+[actions.open]
+name = "Open"
+accel = "Ctrl+o"
+icon = "fas-folder-open"
+[actions.incr-font-size]
+name = "Larger texts"
+accel = "Ctrl+PLUS"
+icon = "fas-folder-open"
+[actions.decr-font-size]
+name = "Smaller texts"
+accel = "Ctrl+MINUS"
+icon = "fas-folder-open"
+[actions.close]
+name = "Close"
+accel = "Ctrl+w"
+#icon = "fas-folder-open"
+[actions.new]
+name = "New"
+accel = "Ctrl+n"
+icon = "far-file"
+[actions.tree-open-file]
+name="Open file"
+icon="far-edit"
+accel="ENTER"
+[actions.tree-new-file]
+name="New file"
+#icon=""
+accel="INS"
+[actions.tree-new-directory]
+name="New directory"
+#icon=""
+accel="Alt+INS"
+[actions.tree-rename-file]
+name="Rename file"
+#icon=""
+accel="F2"
+[actions.tree-delete-file]
+name="Delete file"
+#icon=""
+accel="DEL"
+[actions.go-up]
+name="Go up"
+#icon=""
+#accel=""
+[actions.go-into]
+name="Go into"
+#icon=""
+#accel=""
+[actions.refresh]
+name="Refresh"
+#icon=""
+#accel=""
+[actions.expand-tree]
+name="Expand tree"
+#icon=""
+#accel=""
+[actions.open-in-explorer]
+name="Show in Explorer"
+#icon=""
+#accel=""
+[actions.xdg-open]
+name="Open with System"
+#icon=""
+#accel=""
+
diff --git a/ide/src/main/resources/css/style.css b/ide/src/main/resources/css/style.css
new file mode 100644
index 000000000..3d600da51
--- /dev/null
+++ b/ide/src/main/resources/css/style.css
@@ -0,0 +1,87 @@
+/*
+$base03: #002b36;
+$base02: #073642;
+$base01: #586e75;
+$base00: #657b83;
+$base0: #839496;
+$base1: #93a1a1;
+$base2: #eee8d5;
+$base3: #fdf6e3;
+$yellow: #b58900;
+$orange: #cb4b16;
+$red: #dc322f;
+$magenta: #d33682;
+$violet: #6c71c4;
+$blue: #268bd2;
+$cyan: #2aa198;
+$green: #859900;
+*/
+
+.styled-text-area .text {
+ -fx-background-color: #93a1a1;
+}
+
+.error-char {
+ background: #dc322f;
+}
+
+.separator {
+ -fx-fill: #268bd2;
+}
+
+.structural {
+ -fx-fill: #6c71c4;
+ -fx-font-weight: bold;
+}
+
+.literal {
+ -fx-fill: #cb4b16;
+}
+
+.identifier {
+ -fx-fill: #b58900;
+
+}
+
+.fancy-identifier {
+ -fx-fill: #b58900;
+ -fx-font-weight: bold;
+}
+
+.comment {
+ -fx-fill: #859900;
+}
+
+.datatype {
+ -fx-fill: #b58900;
+}
+
+.control {
+ -fx-fill: #6c71c4;
+}
+
+.operators {
+ -fx-fill: #6c71c4;
+}
+
+
+/*
+@mixin rebase($rebase03,$rebase02,$rebase01,$rebase00,$rebase0,$rebase1,$rebase2,$rebase3)
+{
+ background-color:$rebase03;
+ color:$rebase0;
+ * { color:$rebase0; }
+ h1,h2,h3,h4,h5,h6 { color:$rebase1; border-color: $rebase0; }
+ a, a:active, a:visited { color: $rebase1; }
+}
+@mixin accentize($accent) {
+ a, a:active, a:visited, code.url { color: $accent; }
+ h1,h2,h3,h4,h5,h6 {color:$accent}
+}
+html, .light { @include rebase($base3,$base2,$base1,$base0,$base00,$base01,$base02,$base03)}
+.dark { @include rebase($base03,$base02,$base01,$base00,$base0,$base1,$base2,$base3)}
+html * {
+ color-profile: sRGB;
+ rendering-intent: auto;
+}
+*/
\ No newline at end of file
diff --git a/lang/build.gradle b/lang/build.gradle
index 71e079172..614c01480 100644
--- a/lang/build.gradle
+++ b/lang/build.gradle
@@ -39,4 +39,4 @@ compileTestKotlin.dependsOn generateTestGrammarSource
test {
exclude '**/SFCLangParserTest.class'
-}
\ No newline at end of file
+}
diff --git a/lang/src/main/kotlin/edu/kit/iti/formal/automation/analysis/RewriteEnums.kt b/lang/src/main/kotlin/edu/kit/iti/formal/automation/analysis/RewriteEnums.kt
index 1cc7d2b2a..9af38e0c3 100644
--- a/lang/src/main/kotlin/edu/kit/iti/formal/automation/analysis/RewriteEnums.kt
+++ b/lang/src/main/kotlin/edu/kit/iti/formal/automation/analysis/RewriteEnums.kt
@@ -7,6 +7,7 @@ import edu.kit.iti.formal.automation.st.ast.Expression
import edu.kit.iti.formal.automation.st.ast.Literal
import edu.kit.iti.formal.automation.st.ast.SymbolicReference
import edu.kit.iti.formal.automation.st.util.AstMutableVisitor
+import java.util.*
object RewriteEnums : AstMutableVisitor() {
private var lastScope: Scope? = null
@@ -18,7 +19,7 @@ object RewriteEnums : AstMutableVisitor() {
override fun visit(literal: Literal): Expression {
when (literal) {
- is EnumLit -> literal.value = literal.value.toUpperCase()
+ is EnumLit -> literal.value = literal.value.uppercase(Locale.getDefault())
else -> {}
}
return literal
@@ -30,11 +31,11 @@ object RewriteEnums : AstMutableVisitor() {
val value = symbolicReference.identifier
if (scope.resolveVariable(symbolicReference) == null) {
val enum0 = scope.resolveEnumByValue(value)
- if (enum0 != null) return EnumLit(RefTo(enum0), value.toUpperCase())
+ if (enum0 != null) return EnumLit(RefTo(enum0), value.uppercase(Locale.getDefault()))
val enum1 = scope.resolveEnum(value)
if (enum1 != null && symbolicReference.hasSub())
- return EnumLit(RefTo(enum1), symbolicReference.sub!!.identifier.toUpperCase())
+ return EnumLit(RefTo(enum1), symbolicReference.sub!!.identifier.uppercase(Locale.getDefault()))
}
}
return symbolicReference
diff --git a/lang/src/main/kotlin/edu/kit/iti/formal/automation/analysis/ai.kt b/lang/src/main/kotlin/edu/kit/iti/formal/automation/analysis/ai.kt
index 1db1fa22a..985297f56 100644
--- a/lang/src/main/kotlin/edu/kit/iti/formal/automation/analysis/ai.kt
+++ b/lang/src/main/kotlin/edu/kit/iti/formal/automation/analysis/ai.kt
@@ -607,12 +607,12 @@ private operator fun Interval.minus(ri: Interval): Interval {
private operator fun Interval.times(ri: Interval): Interval {
//[x_1, x_2] \cdot [y_1, y_2] = [\min(x_1 y_1,x_1 y_2,x_2 y_1,x_2 y_2), \max(x_1 y_1,x_1 y_2,x_2 y_1,x_2 y_2)]
val s = listOf(a * ri.a, a * ri.b, b * ri.a, b * ri.b)
- return Interval(s.min()!!, s.max()!!)
+ return Interval(s.minOrNull()!!, s.maxOrNull()!!)
}
private fun Interval.power(ri: Interval): Interval {
val s = listOf(a.pow(ri.a), a.pow(ri.b), b.pow(ri.a), b.pow(ri.b))
- return Interval(floor(s.min()!!).toInt(), ceil(s.max()!!).toInt())
+ return Interval(floor(s.minOrNull()!!).toInt(), ceil(s.maxOrNull()!!).toInt())
}
private fun Int.pow(a: Int): Double = Math.pow(this.toDouble(), a.toDouble())
@@ -624,8 +624,8 @@ private operator fun Interval.div(ri: Interval): Interval {
val x = 1.0 / ri.b
val y = 1.0 / ri.a
val s = listOf(a * x, a * y, b * x, b * y)
- val mi = floor(s.min()!!).toInt()
- val ma = ceil(s.max()!!).toInt()
+ val mi = floor(s.minOrNull()!!).toInt()
+ val ma = ceil(s.maxOrNull()!!).toInt()
return Interval(mi, ma)
}
diff --git a/lang/src/main/kotlin/edu/kit/iti/formal/automation/analysis/checks.kt b/lang/src/main/kotlin/edu/kit/iti/formal/automation/analysis/checks.kt
index ce8c7c27b..50bdd508a 100644
--- a/lang/src/main/kotlin/edu/kit/iti/formal/automation/analysis/checks.kt
+++ b/lang/src/main/kotlin/edu/kit/iti/formal/automation/analysis/checks.kt
@@ -13,6 +13,8 @@ import edu.kit.iti.formal.automation.st.util.AstVisitorWithScope
import edu.kit.iti.formal.util.dlevenshtein
import org.antlr.v4.runtime.Token
import java.lang.Throwable
+import java.util.*
+import kotlin.collections.ArrayList
import kotlin.math.ceil
import kotlin.math.log
@@ -23,7 +25,7 @@ fun getCheckers(reporter: Reporter) = listOf(CheckForTypes(reporter), CheckForLi
* Percentage of changed characters.
*/
fun variableSimilarity(expected: String, defined: String): Double =
- dlevenshtein(expected.toLowerCase(), defined.toLowerCase()).toDouble() / expected.length
+ dlevenshtein(expected.lowercase(Locale.getDefault()), defined.lowercase(Locale.getDefault())).toDouble() / expected.length
fun Iterable.similarCandidates(reference: String, threshold: Double = .9) =
this.map { it to variableSimilarity(reference, it) }
diff --git a/lang/src/main/kotlin/edu/kit/iti/formal/automation/datatypes/dt.kt b/lang/src/main/kotlin/edu/kit/iti/formal/automation/datatypes/dt.kt
index f5614b2f6..ceb6813ec 100644
--- a/lang/src/main/kotlin/edu/kit/iti/formal/automation/datatypes/dt.kt
+++ b/lang/src/main/kotlin/edu/kit/iti/formal/automation/datatypes/dt.kt
@@ -17,7 +17,7 @@ import kotlin.math.ln
sealed class AnyDt(override var name: String = "ANY") : Identifiable {
constructor() : this("") {
- name = javaClass.getSimpleName().toUpperCase()
+ name = javaClass.getSimpleName().uppercase(Locale.getDefault())
}
abstract fun repr(obj: Any): String
@@ -66,7 +66,7 @@ open class AnyNum : AnyDt("ANY_NUM") {
abstract class AnyReal : AnyNum() {
override fun repr(obj: Any): String {
val d = obj as BigDecimal
- return name.toUpperCase() + "#" + d
+ return name.uppercase(Locale.getDefault()) + "#" + d
}
override fun accept(visitor: DataTypeVisitorNN) = visitor.visit(this)
@@ -102,7 +102,7 @@ abstract class AnyBit(var bitLength: Int = 0) : AnyDt() {
override fun repr(obj: Any): String {
if (obj is Bits)
if (obj.register > 0)
- return (name.toUpperCase() + "#2#" + java.lang.Long.toBinaryString(obj.register))
+ return (name.uppercase(Locale.getDefault()) + "#2#" + java.lang.Long.toBinaryString(obj.register))
return ""
}
@@ -329,7 +329,7 @@ abstract class IECString : AnyDt() {
val pattern = Pattern.compile("[\$]([\"'NLRTnlrt]|[0-9]{$bytes})")
val m = pattern.matcher(str)
while (m.find()) {
- val replacement = when (m.group(1).toUpperCase()) {
+ val replacement = when (m.group(1).uppercase(Locale.getDefault())) {
"$" -> "$"
"'" -> "'"
"\"" -> "\""
@@ -393,8 +393,10 @@ class EnumerateType(name: String = "ENUM",
return ceil(ln(allowedValues.size.toDouble())).toInt()
}
- constructor(name: String, allowedValues: MutableList,
- defValue: String = allowedValues[0]) : this(name) {
+ constructor(
+ name: String, allowedValues: MutableList,
+ defValue: String = allowedValues[0]
+ ) : this(name) {
allowedValues.forEachIndexed { index, s -> this.allowedValues[s] = index }
this.defValue = defValue
}
@@ -402,9 +404,9 @@ class EnumerateType(name: String = "ENUM",
constructor(etd: EnumerationTypeDeclaration) : this() {
name = etd.name
etd.allowedValues.zip(etd.values).forEach { (a, b) ->
- allowedValues.put(a.text!!.toUpperCase(), b)
+ allowedValues.put(a.text!!.uppercase(Locale.getDefault()), b)
}
- defValue = etd.allowedValues[0].text.toUpperCase()
+ defValue = etd.allowedValues[0].text.uppercase(Locale.getDefault())
}
override fun repr(obj: Any): String {
@@ -414,7 +416,7 @@ class EnumerateType(name: String = "ENUM",
override fun accept(visitor: DataTypeVisitorNN) = visitor.visit(this)
fun isAllowedValue(value: String) = this.allowedValues.contains(value)
- operator fun contains(textValue: String) = textValue.toUpperCase() in allowedValues
+ operator fun contains(textValue: String) = textValue.uppercase(Locale.getDefault()) in allowedValues
override fun toString(): String = "ENUM $name"
@@ -452,7 +454,7 @@ class EnumerateType(name: String = "ENUM",
open class AnyInt(var bitLength: kotlin.Int = 0, var isSigned: Boolean = false) : AnyNum() {
init {
- name = javaClass.getSimpleName().toUpperCase()
+ name = javaClass.getSimpleName().uppercase(Locale.getDefault())
}
open val upperBound: BigInteger
@@ -474,7 +476,7 @@ open class AnyInt(var bitLength: kotlin.Int = 0, var isSigned: Boolean = false)
override fun repr(obj: Any): String {
- return javaClass.getSimpleName().toUpperCase() + "#" + obj
+ return javaClass.getSimpleName().uppercase(Locale.getDefault()) + "#" + obj
}
open fun next(): AnyInt? = null
diff --git a/lang/src/main/kotlin/edu/kit/iti/formal/automation/datatypes/values/Value.kt b/lang/src/main/kotlin/edu/kit/iti/formal/automation/datatypes/values/Value.kt
index 3858493fb..107f41317 100644
--- a/lang/src/main/kotlin/edu/kit/iti/formal/automation/datatypes/values/Value.kt
+++ b/lang/src/main/kotlin/edu/kit/iti/formal/automation/datatypes/values/Value.kt
@@ -26,6 +26,7 @@ import edu.kit.iti.formal.automation.datatypes.*
import edu.kit.iti.formal.automation.st.ast.*
import java.math.BigDecimal
import java.math.BigInteger
+import java.util.*
/**
* Created by weigl on 11.06.14.
@@ -111,7 +112,7 @@ class VTimeOfDay(dt: AnyDate.TIME_OF_DAY, v: TimeofDayData) : Value(dt, v.toUpperCase()) {
+class VAnyEnum(dt: EnumerateType, v: String) : Value(dt, v.uppercase(Locale.getDefault())) {
override fun assignTo(ref: SymbolicReference) = StatementList(ref assignTo EnumLit(dataType, value))
}
diff --git a/lang/src/main/kotlin/edu/kit/iti/formal/automation/experimental/java.kt b/lang/src/main/kotlin/edu/kit/iti/formal/automation/experimental/java.kt
index 491352d71..7be6ef396 100644
--- a/lang/src/main/kotlin/edu/kit/iti/formal/automation/experimental/java.kt
+++ b/lang/src/main/kotlin/edu/kit/iti/formal/automation/experimental/java.kt
@@ -12,6 +12,7 @@ import edu.kit.iti.formal.automation.st.util.AstVisitor
import edu.kit.iti.formal.automation.st.util.AstVisitorWithScope
import edu.kit.iti.formal.util.CodeWriter
import java.io.StringWriter
+import java.util.*
/**
*
@@ -159,7 +160,7 @@ class JavaExportVisitor(val packageName: String, val rootClass: String) {
override fun visit(enumerationTypeDeclaration: EnumerationTypeDeclaration) {
cw.nl().cblock("public enum ${enumerationTypeDeclaration.name} {", "}") {
val v = enumerationTypeDeclaration.allowedValues
- .joinToString(", ", "", ";") { it.text.toUpperCase() }
+ .joinToString(", ", "", ";") { it.text.uppercase(Locale.getDefault()) }
cw.write(v)
}
cw.nl()
@@ -264,7 +265,7 @@ class JavaExportVisitor(val packageName: String, val rootClass: String) {
}
override fun visit(enumeration: CaseCondition.Enumeration) {
- val n = (enumeration.start).value.toUpperCase()
+ val n = (enumeration.start).value.uppercase(Locale.getDefault())
cw.nl().write("case $n:")
}
@@ -390,7 +391,7 @@ class JavaExportVisitor(val packageName: String, val rootClass: String) {
a.milliseconds.toString()
}
is EnumLit -> {
- literal.dataType.identifier!! + "." + literal.value.toUpperCase()
+ literal.dataType.identifier!! + "." + literal.value.uppercase(Locale.getDefault())
}
else -> td?.toString() ?: ""
}
diff --git a/lang/src/main/kotlin/edu/kit/iti/formal/automation/operators/Operators.kt b/lang/src/main/kotlin/edu/kit/iti/formal/automation/operators/Operators.kt
index 33db20b2c..a30664bab 100644
--- a/lang/src/main/kotlin/edu/kit/iti/formal/automation/operators/Operators.kt
+++ b/lang/src/main/kotlin/edu/kit/iti/formal/automation/operators/Operators.kt
@@ -24,6 +24,7 @@ package edu.kit.iti.formal.automation.operators
import edu.kit.iti.formal.automation.datatypes.AnyBit
import edu.kit.iti.formal.automation.datatypes.AnyNum
+import java.util.*
/**
* Facade.
@@ -82,10 +83,10 @@ object Operators {
}
fun lookup(operator: String): Operator {
- if (operator.toUpperCase() !in TABLE) {
+ if (operator.uppercase(Locale.getDefault()) !in TABLE) {
throw IllegalArgumentException("Operator $operator is not defined")
}
- return TABLE[operator.toUpperCase()]!!
+ return TABLE[operator.uppercase(Locale.getDefault())]!!
}
fun register(op: Operator) = register(op.symbol, op)
diff --git a/lang/src/main/kotlin/edu/kit/iti/formal/automation/parser/SyntaxErrorReporter.kt b/lang/src/main/kotlin/edu/kit/iti/formal/automation/parser/SyntaxErrorReporter.kt
index 17e7b4136..915764cbc 100644
--- a/lang/src/main/kotlin/edu/kit/iti/formal/automation/parser/SyntaxErrorReporter.kt
+++ b/lang/src/main/kotlin/edu/kit/iti/formal/automation/parser/SyntaxErrorReporter.kt
@@ -11,7 +11,7 @@ import java.util.function.Supplier
*/
class SyntaxErrorReporter : BaseErrorListener() {
var isPrint = true
- private val errors = ArrayList()
+ val errors = ArrayList()
override fun syntaxError(recognizer: Recognizer<*, *>?, offendingSymbol: Any?, line: Int,
charPositionInLine: Int, msg: String?, e: RecognitionException?) {
diff --git a/lang/src/main/kotlin/edu/kit/iti/formal/automation/scope/Scope.kt b/lang/src/main/kotlin/edu/kit/iti/formal/automation/scope/Scope.kt
index 24916c683..4da767d51 100644
--- a/lang/src/main/kotlin/edu/kit/iti/formal/automation/scope/Scope.kt
+++ b/lang/src/main/kotlin/edu/kit/iti/formal/automation/scope/Scope.kt
@@ -189,8 +189,11 @@ data class Scope(val variables: VariableScope = VariableScope())
fun resolveFunctionBlock(key: String) = functionBlocks.lookup(key)
fun resolveFunction(key: String) = functions.lookup(key)
- fun registerProgram(programDeclaration: ProgramDeclaration) = programs.register(programDeclaration.name!!, programDeclaration)
- fun registerFunction(functionDeclaration: FunctionDeclaration) = functions.register(functionDeclaration.name, functionDeclaration)
+ fun registerProgram(programDeclaration: ProgramDeclaration) =
+ programs.register(programDeclaration.name!!, programDeclaration)
+
+ fun registerFunction(functionDeclaration: FunctionDeclaration) =
+ functions.register(functionDeclaration.name, functionDeclaration)
fun registerFunctionBlock(fblock: FunctionBlockDeclaration) = functionBlocks.register(fblock.name, fblock)
@@ -200,8 +203,8 @@ data class Scope(val variables: VariableScope = VariableScope())
if (dt is EnumerationTypeDeclaration) {
val edt = dt.getDataType(this)
dt.allowedValues
- .map { it.text!! }
- .forEach { allowedEnumValues[it.toUpperCase()] = edt }
+ .map { it.text!! }
+ .forEach { allowedEnumValues[it.uppercase(Locale.getDefault())] = edt }
}
}
@@ -218,8 +221,8 @@ data class Scope(val variables: VariableScope = VariableScope())
//if (a && b || a && c || b && c) {
val ambigue = arrayListOf(a, b, c, d)
- .map { if (it != null) 1 else 0 }
- .sum() > 1
+ .map { if (it != null) 1 else 0 }
+ .sum() > 1
if (ambigue) {
System.err.println("Ambiguity in Name Resolution for: $name")
@@ -269,11 +272,11 @@ data class Scope(val variables: VariableScope = VariableScope())
fun registerClass(clazz: ClassDeclaration) =
- classes.register(clazz.name, clazz)
+ classes.register(clazz.name, clazz)
fun resolveClass(key: String) = classes.lookup(key)
fun registerInterface(interfaceDeclaration: InterfaceDeclaration) =
- interfaces.register(interfaceDeclaration.name, interfaceDeclaration)
+ interfaces.register(interfaceDeclaration.name, interfaceDeclaration)
fun registerMethod(md: MethodDeclaration) = methods.register(md.name, md)
fun resolveInterface(key: String) = interfaces.lookup(key)
@@ -338,9 +341,9 @@ data class Scope(val variables: VariableScope = VariableScope())
}
fun resolveEnumByValue(value: String): EnumerateType? =
- value.toUpperCase().let {
- this.allowedEnumValues[it] ?: parent?.resolveEnumByValue(it)
- }
+ value.uppercase(Locale.getDefault()).let {
+ this.allowedEnumValues[it] ?: parent?.resolveEnumByValue(it)
+ }
/**
* Construct a complete map of values to EnumerationType
@@ -354,11 +357,11 @@ data class Scope(val variables: VariableScope = VariableScope())
//region call resolver
fun resolveInvocation(callee: SymbolicReference): Invoked? {
val resolvers = listOf(
- this::resolveProgramInvocation,
- this::resolveActionInvocation,
- this::resolveFunctionBlockInvocation,
- this::resolveFunctionInvocation
- //, this::resolveMethodInvocation
+ this::resolveProgramInvocation,
+ this::resolveActionInvocation,
+ this::resolveFunctionBlockInvocation,
+ this::resolveFunctionInvocation
+ //, this::resolveMethodInvocation
)
val resolved = resolvers.map { it(callee) }.filter { it != null }
diff --git a/lang/src/main/kotlin/edu/kit/iti/formal/automation/st/HccPrinter.kt b/lang/src/main/kotlin/edu/kit/iti/formal/automation/st/HccPrinter.kt
index b49dbdeca..533f1aa20 100644
--- a/lang/src/main/kotlin/edu/kit/iti/formal/automation/st/HccPrinter.kt
+++ b/lang/src/main/kotlin/edu/kit/iti/formal/automation/st/HccPrinter.kt
@@ -10,6 +10,7 @@ import edu.kit.iti.formal.automation.st.ast.*
import edu.kit.iti.formal.util.CodeWriter
import edu.kit.iti.formal.util.joinInto
import edu.kit.iti.formal.util.meta
+import java.util.*
open class HccPrinter(sb: CodeWriter = CodeWriter(), noPreamble: Boolean = false) : StructuredTextPrinter(sb) {
init {
@@ -169,7 +170,7 @@ open class HccPrinter(sb: CodeWriter = CodeWriter(), noPreamble: Boolean = false
val returnType = functionDeclaration.returnType.identifier
if (!(returnType == null || returnType.isEmpty()))
- sb.printf(returnType.toLowerCase()).printf(" ${functionDeclaration.name}( ")
+ sb.printf(returnType.lowercase(Locale.getDefault())).printf(" ${functionDeclaration.name}( ")
functionDeclaration.scope.variables.filter { it.isInput || it.isInOut }.forEachIndexed { i, it ->
if (i != 0) {
sb.printf(", ")
@@ -245,7 +246,7 @@ open class HccPrinter(sb: CodeWriter = CodeWriter(), noPreamble: Boolean = false
} else if (simpleTypeDeclaration.baseType.obj is UINT) {
sb.printf("unsigned int")
} else {
- sb.printf(simpleTypeDeclaration.baseType.identifier!!.toLowerCase())
+ sb.printf(simpleTypeDeclaration.baseType.identifier!!.lowercase(Locale.getDefault()))
}
@@ -274,7 +275,7 @@ open class HccPrinter(sb: CodeWriter = CodeWriter(), noPreamble: Boolean = false
}
is SpecialCommentMeta.HavocComment -> {
sb.nl()
- val haveocName = "nondet_${meta.dataType.name.toLowerCase()}();"
+ val haveocName = "nondet_${meta.dataType.name.lowercase(Locale.getDefault())}();"
//sb.printf(" ").printf(haveocName).printf(" = _;").nl() //uninitialised Var
sb.printf(meta.variable).printf(" = ").printf(haveocName)
}
diff --git a/lang/src/main/kotlin/edu/kit/iti/formal/automation/st/StructuredTextPrinter.kt b/lang/src/main/kotlin/edu/kit/iti/formal/automation/st/StructuredTextPrinter.kt
index bd6ec8f4c..8bfee2df9 100644
--- a/lang/src/main/kotlin/edu/kit/iti/formal/automation/st/StructuredTextPrinter.kt
+++ b/lang/src/main/kotlin/edu/kit/iti/formal/automation/st/StructuredTextPrinter.kt
@@ -227,7 +227,7 @@ open class StructuredTextPrinter(var sb: CodeWriter = CodeWriter()) : AstVisitor
val QUOTED_IDENTIFIER = listOf("STEP", "END_STEP", "TRANSITION", "END_TRANSITION", "INITIAL_STEP", "FROM")
private fun quoteIdentifier(identifier: String): String {
- return if (identifier.toUpperCase() in QUOTED_IDENTIFIER) {
+ return if (identifier.uppercase(Locale.getDefault()) in QUOTED_IDENTIFIER) {
"`$identifier`"
} else {
identifier
@@ -587,37 +587,44 @@ open class StructuredTextPrinter(var sb: CodeWriter = CodeWriter()) : AstVisitor
fun print(prefix: Any?, suffix: Any) =
(if (prefix != null) "$prefix#" else "") + suffix
- sb.printf(when (literal) {
- is IntegerLit -> print(literal.dataType.obj?.name, literal.value.abs())
- is RealLit -> print(literal.dataType.obj?.name, literal.value.abs())
- is EnumLit -> print(literal.dataType.obj?.name, literal.value)
- is ToDLit -> {
- val (h, m, s, ms) = literal.value
- print(literal.dataType().name, "$h:$m:$s.$ms")
- }
- is DateLit -> {
- val (y, m, d) = literal.value
- print(literal.dataType().name, "$y-$m-$d")
- }
- is DateAndTimeLit -> {
- val (y, mo, d) = literal.value.date
- val (h, m, s, ms) = literal.value.tod
- print(literal.dataType().name, "$y-$mo-$d-$h:$m:$s.$ms")
- }
- is StringLit -> {
- if (literal.dataType() is IECString.WSTRING) "\"${literal.value}\""
- else "'${literal.value}'"
- }
- is NullLit -> "null"
- is TimeLit -> {
- print(literal.dataType().name, "${literal.value.milliseconds}ms")
- }
- is BooleanLit -> literal.value.toString().toUpperCase()
- is BitLit -> {
- print(literal.dataType.obj?.name, "2#" + literal.value.toString(2))
- }
- is UnindentifiedLit -> literal.value
- })
+ sb.printf(
+ when (literal) {
+ is IntegerLit -> print(literal.dataType.obj?.name, literal.value.abs())
+ is RealLit -> print(literal.dataType.obj?.name, literal.value.abs())
+ is EnumLit -> print(literal.dataType.obj?.name, literal.value)
+ is ToDLit -> {
+ val (h, m, s, ms) = literal.value
+ print(literal.dataType().name, "$h:$m:$s.$ms")
+ }
+
+ is DateLit -> {
+ val (y, m, d) = literal.value
+ print(literal.dataType().name, "$y-$m-$d")
+ }
+
+ is DateAndTimeLit -> {
+ val (y, mo, d) = literal.value.date
+ val (h, m, s, ms) = literal.value.tod
+ print(literal.dataType().name, "$y-$mo-$d-$h:$m:$s.$ms")
+ }
+
+ is StringLit -> {
+ if (literal.dataType() is IECString.WSTRING) "\"${literal.value}\""
+ else "'${literal.value}'"
+ }
+
+ is NullLit -> "null"
+ is TimeLit -> {
+ print(literal.dataType().name, "${literal.value.milliseconds}ms")
+ }
+
+ is BooleanLit -> literal.value.toString().uppercase(Locale.getDefault())
+ is BitLit -> {
+ print(literal.dataType.obj?.name, "2#" + literal.value.toString(2))
+ }
+
+ is UnindentifiedLit -> literal.value
+ })
}
override fun visit(arrayinit: ArrayInitialization) {
diff --git a/lang/src/main/kotlin/edu/kit/iti/formal/automation/st/TranslationSfcToStPipeline.kt b/lang/src/main/kotlin/edu/kit/iti/formal/automation/st/TranslationSfcToStPipeline.kt
index f2793d8cc..52ab0ed7d 100644
--- a/lang/src/main/kotlin/edu/kit/iti/formal/automation/st/TranslationSfcToStPipeline.kt
+++ b/lang/src/main/kotlin/edu/kit/iti/formal/automation/st/TranslationSfcToStPipeline.kt
@@ -12,6 +12,7 @@ import edu.kit.iti.formal.automation.st.ast.BooleanLit.Companion.LTRUE
import edu.kit.iti.formal.automation.st.ast.SFCActionQualifier.Qualifier.*
import edu.kit.iti.formal.automation.st.util.AstMutableVisitor
import org.antlr.v4.runtime.CommonToken
+import java.util.*
import java.util.concurrent.Callable
private val SFCStep.onEntry: String?
@@ -518,11 +519,13 @@ object Falling : ActionQualifierHandler(FALLING) {
}
}
-data class PipelineData(val network: SFCNetwork, val name: String, val index: Int, val scope: Scope,
- val finalScan: Boolean, val sfcFlags: Boolean, val maxNeededTokens: TokenAmount) {
+data class PipelineData(
+ val network: SFCNetwork, val name: String, val index: Int, val scope: Scope,
+ val finalScan: Boolean, val sfcFlags: Boolean, val maxNeededTokens: TokenAmount
+) {
val tokenIsBoundedTo1: Boolean = maxNeededTokens is TokenAmount.Bounded && maxNeededTokens.max == 1
val transitions: Map, List> = network.steps.flatMap { it.outgoing }.distinct()
- .sortedByDescending { it.priority }.groupBy { it.from }
+ .sortedByDescending { it.priority }.groupBy { it.from }
val actions: MutableMap = mutableMapOf()
val specialResetStatements: StatementList = StatementList()
@@ -541,20 +544,20 @@ data class PipelineData(val network: SFCNetwork, val name: String, val index: In
val stateName = SymbolicReference(if (index <= 0) "_state" else "_${index}_state")
val enumName =
- (if (index <= 0) "STATES_$name" else "STATES_$name\$${index}").toUpperCase()
+ (if (index <= 0) "STATES_$name" else "STATES_$name\$${index}").uppercase(Locale.getDefault())
val stateEnumType =
- createEnumerationTypeForSfc(enumName, network, this::enumStepName)
+ createEnumerationTypeForSfc(enumName, network, this::enumStepName)
val stateEnumTypeDeclaration by lazy {
val enumType = EnumerationTypeDeclaration(enumName)
val et = stateEnumType
enumType.addValue(CommonToken(IEC61131Lexer.IDENTIFIER, enumStepName(stepName(et.defValue))))
et.allowedValues
- .map { it.key }
- .filter { it != et.defValue }
- .forEach {
- enumType.addValue(CommonToken(IEC61131Lexer.IDENTIFIER, enumStepName(stepName(it))))
- }
+ .map { it.key }
+ .filter { it != et.defValue }
+ .forEach {
+ enumType.addValue(CommonToken(IEC61131Lexer.IDENTIFIER, enumStepName(stepName(it))))
+ }
//enumType.initialization = IdentifierInitializer(value = enumStepName(network.initialStep!!.name))
//scope.dataTypes.register(enumName, enumType)
//specialResetStatements += enumName.assignTo(enumType.initialization!!.value!!)
@@ -577,13 +580,13 @@ data class PipelineData(val network: SFCNetwork, val name: String, val index: In
fun enumValue(step: SFCStep) = EnumLit(stateEnumType, enumStepName(stepName(step.name)))
fun stepName(stepName: String, idx: Int = index, sfcName: String = name): String =
- if (idx <= 0) stepName else "_${idx}_$stepName"
+ if (idx <= 0) stepName else "_${idx}_$stepName"
//0 -> "$sfcName$stepName"
//else -> "$sfcName${idx}_$stepName"
fun enumStepName(stepName: String) =
- if (index <= 0) stepName else "_${index}_$stepName"
+ if (index <= 0) stepName else "_${index}_$stepName"
fun addToScope(name: String, dt: AnyDt, type: Int = 0): VariableDeclaration {
return if (!scope.variables.contains(name)) {
@@ -594,20 +597,30 @@ data class PipelineData(val network: SFCNetwork, val name: String, val index: In
fun addToScope(names: List, dt: AnyDt, type: Int = 0) = names.map { addToScope(it, dt, type) }
fun moduleTON(name: String, input: Expression, pt: Expression) {
- specialResetStatements += InvocationStatement(SymbolicReference(name), mutableListOf(InvocationParameter("IN",
- false, LFALSE), InvocationParameter("PT", false, TimeLit(TimeData()))))
+ specialResetStatements += InvocationStatement(
+ SymbolicReference(name), mutableListOf(
+ InvocationParameter(
+ "IN",
+ false, LFALSE
+ ), InvocationParameter("PT", false, TimeLit(TimeData()))
+ )
+ )
moduleFB(name, "TON", listOf(Pair("IN", input), Pair("PT", pt)))
}
fun moduleRS(name: String, set: Expression, reset1: Expression) {
- specialResetStatements += InvocationStatement(SymbolicReference(name),
- mutableListOf(InvocationParameter("R", false, LTRUE)))
+ specialResetStatements += InvocationStatement(
+ SymbolicReference(name),
+ mutableListOf(InvocationParameter("R", false, LTRUE))
+ )
moduleFB(name, "RS", listOf(Pair("SET", set), Pair("RESET1", reset1)))
}
fun moduleTRIG(name: String, clk: Expression, type: String = "R_TRIG") {
- specialResetStatements += InvocationStatement(SymbolicReference(name),
- mutableListOf(InvocationParameter("CLK", false, LFALSE)))
+ specialResetStatements += InvocationStatement(
+ SymbolicReference(name),
+ mutableListOf(InvocationParameter("CLK", false, LFALSE))
+ )
moduleFB(name, type, listOf(Pair("CLK", clk)))
}
diff --git a/smt/build.gradle b/smt/build.gradle
index 45c5a4e52..3498fb0e6 100644
--- a/smt/build.gradle
+++ b/smt/build.gradle
@@ -40,4 +40,4 @@ generateGrammarSource {
compileJava.dependsOn generateGrammarSource
compileKotlin.dependsOn generateGrammarSource
-compileTestKotlin.dependsOn generateTestGrammarSource
\ No newline at end of file
+compileTestKotlin.dependsOn generateTestGrammarSource
diff --git a/smv/src/main/kotlin/edu/kit/iti/formal/smv/types.kt b/smv/src/main/kotlin/edu/kit/iti/formal/smv/types.kt
index 4ad8bfdec..d5bbd044b 100644
--- a/smv/src/main/kotlin/edu/kit/iti/formal/smv/types.kt
+++ b/smv/src/main/kotlin/edu/kit/iti/formal/smv/types.kt
@@ -27,7 +27,7 @@ data class SMVWordType(
override fun valueOf(str: String) = SWordLiteral(read(str), this)
override fun read(str: String): BigInteger {
- val re = Pattern.compile("(?-)?0(?s|u)d(?\\d+)_(?\\d+)")
+ val re = Pattern.compile("(?-)?0(?[su])d(?\\d+)_(?\\d+)")
val m = re.matcher(str)
if (m.matches()) {
val word = SMVFacade.parseWordLiteral(str)
@@ -82,7 +82,7 @@ object SMVTypes {
object BOOLEAN : SMVType {
override fun valueOf(str: String) = if (str.equals("true", true)) SLiteral.TRUE else SLiteral.FALSE
- override fun format(value: Any): String = value.toString().toUpperCase()
+ override fun format(value: Any): String = value.toString().uppercase(Locale.getDefault())
override fun read(str: String): Any = str.equals("TRUE", true)
override fun repr(): String = "boolean"
override fun allowedValue(obj: Any): Boolean = obj is Boolean
diff --git a/symbex/src/main/kotlin/edu/kit/iti/formal/automation/cpp/translatecpp.kt b/symbex/src/main/kotlin/edu/kit/iti/formal/automation/cpp/translatecpp.kt
index 060ba0409..acdc03149 100644
--- a/symbex/src/main/kotlin/edu/kit/iti/formal/automation/cpp/translatecpp.kt
+++ b/symbex/src/main/kotlin/edu/kit/iti/formal/automation/cpp/translatecpp.kt
@@ -296,7 +296,12 @@ class TranslateToCpp(val out: CodeWriter) : AstVisitor() {
override fun visit(programDeclaration: ProgramDeclaration) {
visit(programDeclaration as PouExecutable, programDeclaration.actions)
val rt = RecordType(programDeclaration.name, programDeclaration.scope.variables)
- out.println("struct ${programDeclaration.name}_t ${programDeclaration.name.toUpperCase()} = ${value(DefaultInitValue.getInit(rt))};")
+ out.println(
+ "struct ${programDeclaration.name}_t ${programDeclaration.name.uppercase(Locale.getDefault())} = ${
+ value(
+ DefaultInitValue.getInit(rt)
+ )
+ };")
}
fun visit(pd: PouExecutable, actions: LookupList) {
@@ -483,8 +488,8 @@ fun generateRunnableStub(cw: CodeWriter, main: PouElements) {
main.elements.forEach { p ->
if (p is ProgramDeclaration) {
val inputs = p.scope.filterByFlags(VariableDeclaration.INPUT, VariableDeclaration.INOUT)
- inputs.forEach { print("havoc(&${p.name.toUpperCase()}.${it.name});").nl() }
- print("${p.name}(& ${p.name.toUpperCase()});").nl()
+ inputs.forEach { print("havoc(&${p.name.uppercase(Locale.getDefault())}.${it.name});").nl() }
+ print("${p.name}(& ${p.name.uppercase(Locale.getDefault())});").nl()
}
}
}
diff --git a/util/src/main/kotlin/edu/kit/iti/formal/util/CodeWriter.kt b/util/src/main/kotlin/edu/kit/iti/formal/util/CodeWriter.kt
index 00b5c0c8e..9f2a554c2 100644
--- a/util/src/main/kotlin/edu/kit/iti/formal/util/CodeWriter.kt
+++ b/util/src/main/kotlin/edu/kit/iti/formal/util/CodeWriter.kt
@@ -2,6 +2,7 @@ package edu.kit.iti.formal.util
import java.io.StringWriter
import java.io.Writer
+import java.util.*
/**
* CodeWriter class.
@@ -39,7 +40,7 @@ open class CodeWriter(var stream: Writer = StringWriter())
}
open fun keyword(keyword: String): CodeWriter {
- return printf(if (uppercaseKeywords) keyword.toUpperCase() else keyword.toLowerCase())
+ return printf(if (uppercaseKeywords) keyword.uppercase(Locale.getDefault()) else keyword.lowercase(Locale.getDefault()))
}
fun nl(): CodeWriter {
diff --git a/xml/src/main/kotlin/edu/kit/iti/formal/automation/plcopenxml/IECXMLFacade.kt b/xml/src/main/kotlin/edu/kit/iti/formal/automation/plcopenxml/IECXMLFacade.kt
index 167626a9c..fe4f72471 100644
--- a/xml/src/main/kotlin/edu/kit/iti/formal/automation/plcopenxml/IECXMLFacade.kt
+++ b/xml/src/main/kotlin/edu/kit/iti/formal/automation/plcopenxml/IECXMLFacade.kt
@@ -4,6 +4,7 @@ import edu.kit.iti.formal.util.CodeWriter
import java.io.*
import java.net.URL
import java.nio.file.Path
+import java.util.*
/**
* @author Alexander Weigl
@@ -33,7 +34,7 @@ object IECXMLFacade {
val SFC_KEYWORDS = setOf("step", "end_step", "transition", "end_transition")
fun quoteVariable(name: String): String =
- if(name.toLowerCase() in SFC_KEYWORDS) "`$name`" else name
+ if (name.lowercase(Locale.getDefault()) in SFC_KEYWORDS) "`$name`" else name
fun quoteStBody(body: String): String {
return body.replace("\\b\\w+\\b".toRegex()) {
diff --git a/xml/src/main/kotlin/edu/kit/iti/formal/automation/plcopenxml/fbdtranslator.kt b/xml/src/main/kotlin/edu/kit/iti/formal/automation/plcopenxml/fbdtranslator.kt
index f080b9c53..ab9f66990 100644
--- a/xml/src/main/kotlin/edu/kit/iti/formal/automation/plcopenxml/fbdtranslator.kt
+++ b/xml/src/main/kotlin/edu/kit/iti/formal/automation/plcopenxml/fbdtranslator.kt
@@ -7,25 +7,26 @@ import edu.kit.iti.formal.util.CodeWriter
import org.jdom2.Element
import org.jdom2.filter.Filters
import org.jdom2.xpath.XPathFactory
+import java.util.*
private val xpathFactory = XPathFactory.instance()
internal fun getVariables(block: Element, child: String) =
- block.getChild(child)?.children?.map { BlockVariable(it) } ?: listOf()
+ block.getChild(child)?.children?.map { BlockVariable(it) } ?: listOf()
internal fun operatorSymbol(name: String) =
- when (name.toLowerCase()) {
- "eq" -> " = "
- "sub" -> " - "
- "add" -> " + "
- "div" -> " / "
- "mult" -> " * "
- "and" -> " AND "
- "or" -> " OR "
- "xor" -> " ^ "
- else -> "/*!! UNKNOWN OP: $name !!*/"
- }
+ when (name.lowercase(Locale.getDefault())) {
+ "eq" -> " = "
+ "sub" -> " - "
+ "add" -> " + "
+ "div" -> " / "
+ "mult" -> " * "
+ "and" -> " AND "
+ "or" -> " OR "
+ "xor" -> " ^ "
+ else -> "/*!! UNKNOWN OP: $name !!*/"
+ }
//TODO: Edges could be negated
//TODO: Storage modifier (S=, R=)
@@ -145,6 +146,7 @@ class FBDTranslator(val fbd: Element, val writer: CodeWriter) {
println("Vendor Elements not supported in FBDs.")
null
}
+
else -> throw IllegalStateException("Xml element: ${block.name}")
}
@@ -204,11 +206,11 @@ sealed class FbdNode(val block: Element, val network: FBDTranslator) {
class FbdBlock(e: Element, network: FBDTranslator) : FbdNode(e, network) {
val type: String by lazy { block.getAttributeValue("typeName") }
val instanceName: String by lazy {
- block.getAttributeValue("instanceName") ?: this.type.toLowerCase()
+ block.getAttributeValue("instanceName") ?: this.type.lowercase(Locale.getDefault())
}
val callType: FBDCallType by lazy {
- when (type.toLowerCase()) {
+ when (type.lowercase(Locale.getDefault())) {
"mux" -> FBDCallType.FUNCTION
"add" -> FBDCallType.OPERATOR
else -> {
@@ -277,6 +279,7 @@ class FbdBlock(e: Element, network: FBDTranslator) : FbdNode(e, network) {
FBDCallType.EXECUTE -> {
Execute(executeBody ?: "//NO BODY WAS FOUND!")
}
+
FBDCallType.OPERATOR -> Operator(instanceName)
FBDCallType.FUNCTION -> Function(instanceName)
FBDCallType.UNKNOWN -> FunctionBlock(instanceName)
diff --git a/xml/src/main/kotlin/fbd.kt b/xml/src/main/kotlin/fbd.kt
index 7fcafb14c..1868083b9 100644
--- a/xml/src/main/kotlin/fbd.kt
+++ b/xml/src/main/kotlin/fbd.kt
@@ -77,7 +77,7 @@ data class FbDiagram(
do {
fixpt = true
for (node in nodes) {
- val predOrder = (pred[node]?.map { it.executionOrder }?.max() ?: 0) + 1
+ val predOrder = (pred[node]?.map { it.executionOrder }?.maxOrNull() ?: 0) + 1
if (node.executionOrder != predOrder) {
fixpt = false
node.executionOrder = predOrder