Skip to content

Commit

Permalink
Resolved almost all issues
Browse files Browse the repository at this point in the history
  • Loading branch information
IgorFilimonov committed May 9, 2024
1 parent d0c9c44 commit 7a4d9f4
Show file tree
Hide file tree
Showing 24 changed files with 199 additions and 180 deletions.
47 changes: 26 additions & 21 deletions src/main/kotlin/automaton/constructor/controller/TestsController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ import automaton.constructor.model.automaton.Automaton
import automaton.constructor.model.data.MemoryUnitDescriptorData
import automaton.constructor.model.data.serializersModule
import automaton.constructor.model.memory.MemoryUnitDescriptor
import automaton.constructor.model.memory.Test
import automaton.constructor.model.memory.TestsForSerializing
import automaton.constructor.model.module.executor.ExecutionStatus
import automaton.constructor.model.module.executor.Executor
import automaton.constructor.utils.I18N
import automaton.constructor.utils.addOnSuccess
import automaton.constructor.utils.createExecutorAndRun
import automaton.constructor.utils.runAsyncWithDialog
import automaton.constructor.view.TestAndResult
import automaton.constructor.view.TestsView
Expand All @@ -25,23 +28,21 @@ import kotlinx.serialization.modules.SerializersModule
import tornadofx.*
import java.io.File

data class Test(val input: List<MemoryUnitDescriptor>)

@Serializable
data class TestsForSerializing(val tests: List<List<MemoryUnitDescriptorData>>, val automatonType: String)

class TestsController(val openedAutomaton: Automaton) : Controller() {
var wereTestsModified = false

private val formatForSerializing = Json {
serializersModule = SerializersModule {
prettyPrint = true
include(MemoryUnitDescriptorData.serializersModule)
}
}

fun saveTests(tests: List<Test>, uiComponent: UIComponent) {
val file = chooseFile(FileChooserMode.Save) ?: return
saveAsync(tests, uiComponent, file)
}

private fun saveAsync(tests: List<Test>, uiComponent: UIComponent, file: File): Task<Unit> {
return uiComponent.runAsyncWithDialog(
I18N.messages.getString("TestsController.Saving"),
Expand All @@ -54,54 +55,58 @@ class TestsController(val openedAutomaton: Automaton) : Controller() {
wereTestsModified = false
}
}

fun createTests() {
val testsWindow = find<TestsView>(mapOf(TestsView::controller to this))
testsWindow.title = "Test"
testsWindow.openWindow()
}

private fun chooseFile(mode: FileChooserMode): File? =
chooseFile(
filters = arrayOf(FileChooser.ExtensionFilter("1", "*.json")),
mode = mode
).firstOrNull()

fun openTests(uiComponent: UIComponent): List<Test> {
val file = chooseFile(FileChooserMode.Single) ?: return listOf()
return openAsync(uiComponent, file).get()
val tests = openAsync(uiComponent, file).get()
return if (tests == null || !openedAutomaton.canUseTheseDescriptors(tests[0].input)) {
error(I18N.messages.getString("TestsController.UnableToOpen"))
listOf()
} else {
tests
}
}
private fun openAsync(uiComponent: UIComponent, file: File): Task<List<Test>> {

private fun openAsync(uiComponent: UIComponent, file: File): Task<List<Test>?> {
return uiComponent.runAsyncWithDialog(
I18N.messages.getString("TestsController.Opening"),
daemon = false
) {
val deserializedTests =
formatForSerializing.decodeFromString<TestsForSerializing>(file.readText())
if (deserializedTests.automatonType != openedAutomaton::class.simpleName!!) {
throw RuntimeException(
I18N.messages.getString("TestsController.UnableToOpen")
)
null
} else {
deserializedTests.tests.map { test -> Test(test.map { it.createDescriptor() }) }
}
deserializedTests.tests.map { test -> Test(test.map { it.createDescriptor() }) }
} addOnSuccess {
wereTestsModified = false
}
}

fun runOnTests(tests: List<Test>) {
val testsAndResults = mutableListOf<TestAndResult>()
tests.forEach { test ->
val memory = openedAutomaton.memoryDescriptors.zip(test.input).map {
(descriptor, content) -> descriptor.createMemoryUnit(content)
}
val executor = Executor(openedAutomaton)
executor.start(memory)
executor.runFor()
val executionResult = when (executor.status) {
ExecutionStatus.ACCEPTED -> I18N.messages.getString("ExecutorController.Executor.Status.Accepted")
ExecutionStatus.REJECTED -> I18N.messages.getString("ExecutorController.Executor.Status.Rejected")
ExecutionStatus.FROZEN -> I18N.messages.getString("ExecutorController.Executor.Status.Frozen")
ExecutionStatus.RUNNING -> I18N.messages.getString("ExecutorController.Executor.Status.Running")
val executorResult = createExecutorAndRun(openedAutomaton, memory)
if (executorResult == null) {
return@runOnTests
}
val graphic = executor.acceptedExeStates.firstOrNull()?.let { executionLeafView(it) }
testsAndResults.add(TestAndResult(test, executionResult, graphic))
testsAndResults.add(TestAndResult(test, executorResult.executionResult, executorResult.graphic))
}
val testsResultsWindow = find<TestsResultsFragment>(mapOf(TestsResultsFragment::testsAndResults to testsAndResults))
testsResultsWindow.title = "Tests results"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package automaton.constructor.controller.module.executor

import automaton.constructor.model.automaton.Automaton
import automaton.constructor.model.module.executor.ExecutionStatus.*
import automaton.constructor.model.module.executor.Executor
import automaton.constructor.model.module.executor.SteppingStrategy
import automaton.constructor.model.module.problems
import automaton.constructor.utils.I18N
import automaton.constructor.view.module.executor.executionLeafView
import automaton.constructor.utils.createExecutorAndRun
import automaton.constructor.utils.getNewExecutorOrNull
import tornadofx.*

class ExecutorController(viewedAutomaton: Automaton, private val uiComponent: UIComponent) : Controller() {
Expand All @@ -20,40 +19,20 @@ class ExecutorController(viewedAutomaton: Automaton, private val uiComponent: UI
it.automaton.clearExecutionStates() // faster analog of executor.stop()
debuggingExecutor = null
} ?: run {
val executor = startNewExecutorOrNull() ?: return@toggleRun
executor.runFor()
val executionResult = when (executor.status) {
ACCEPTED -> I18N.messages.getString("ExecutorController.Executor.Status.Accepted")
REJECTED -> I18N.messages.getString("ExecutorController.Executor.Status.Rejected")
FROZEN -> I18N.messages.getString("ExecutorController.Executor.Status.Frozen")
RUNNING -> I18N.messages.getString("ExecutorController.Executor.Status.Running")
val executorResult = createExecutorAndRun(selectedAutomaton)
if (executorResult != null) {
information(
I18N.messages.getString("ExecutorController.ExecutionResult"),
executorResult.executionResult,
graphic = executorResult.graphic,
title = I18N.messages.getString("Dialog.information"),
owner = uiComponent.currentWindow
)
}
val graphic = executor.acceptedExeStates.firstOrNull()?.let { executionLeafView(it) }
executor.automaton.clearExecutionStates() // faster analog of executor.stop()
information(
I18N.messages.getString("ExecutorController.ExecutionResult"),
executionResult,
graphic = graphic,
title = I18N.messages.getString("Dialog.information"),
owner = uiComponent.currentWindow
)
}
}

fun step(strategy: SteppingStrategy) = debuggingExecutor?.step(strategy) ?: run {
debuggingExecutor = startNewExecutorOrNull()
}

private fun startNewExecutorOrNull(): Executor? {
if (selectedAutomaton.problems.isNotEmpty()) {
error(
I18N.messages.getString("ExecutorController.Error.ExecutionFailed"),
selectedAutomaton.problems.joinToString("\n") { it.message },
title = I18N.messages.getString("Dialog.error"),
owner = uiComponent.currentWindow
)
return null
}
return Executor(selectedAutomaton).apply { start() }
debuggingExecutor = getNewExecutorOrNull(selectedAutomaton)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import automaton.constructor.model.action.transition.RemoveTransitionAction
import automaton.constructor.model.element.*
import automaton.constructor.model.memory.MemoryUnit
import automaton.constructor.model.memory.MemoryUnitDescriptor
import automaton.constructor.model.memory.tape.MultiTrackTapeDescriptor
import automaton.constructor.model.module.AutomatonModule
import automaton.constructor.model.property.EPSILON_VALUE
import automaton.constructor.model.transformation.AutomatonTransformation
Expand Down Expand Up @@ -240,6 +241,20 @@ abstract class AbstractAutomaton(

private val modules = mutableMapOf<(Automaton) -> AutomatonModule, AutomatonModule>()

override fun canUseTheseDescriptors(newDescriptors: List<MemoryUnitDescriptor>): Boolean {
if (newDescriptors.size != memoryDescriptors.size) {
return false
}
for (index in memoryDescriptors.indices) {
if (memoryDescriptors[index]::class != newDescriptors[index]::class ||
memoryDescriptors[index] is MultiTrackTapeDescriptor &&
(memoryDescriptors[index] as MultiTrackTapeDescriptor).trackCount !=
(newDescriptors[index] as MultiTrackTapeDescriptor).trackCount) {
return false
}
}
return true
}

companion object {
private const val STATE_NAME_PREFIX = "S"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ interface Automaton {
* it's not invoked again and cached result of the previous invocation is returned
*/
fun <T : AutomatonModule> getModule(moduleFactory: (Automaton) -> T): T

fun canUseTheseDescriptors(newDescriptors: List<MemoryUnitDescriptor>): Boolean
}

// Get automaton characteristics
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import automaton.constructor.model.action.transition.SimplifyRegexEntirelyTransi
import automaton.constructor.model.action.transition.SimplifyRegexTransitionAction
import automaton.constructor.model.automaton.flavours.AutomatonWithInputTape
import automaton.constructor.model.data.FiniteAutomatonData
import automaton.constructor.model.memory.MemoryUnitDescriptor
import automaton.constructor.model.memory.tape.InputTapeDescriptor
import automaton.constructor.model.transformation.DeterminizeAutomatonAction
import automaton.constructor.utils.I18N
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import automaton.constructor.model.action.state.MooreToMealyAction
import automaton.constructor.model.automaton.flavours.AutomatonWithInputTape
import automaton.constructor.model.automaton.flavours.AutomatonWithOutputTape
import automaton.constructor.model.data.MealyMooreMachineData
import automaton.constructor.model.memory.MemoryUnitDescriptor
import automaton.constructor.model.memory.tape.InputTapeDescriptor
import automaton.constructor.model.memory.tape.OutputTapeDescriptor
import automaton.constructor.model.transformation.StatewiseTransformationAction
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package automaton.constructor.model.automaton

import automaton.constructor.model.automaton.flavours.AutomatonWithTapes
import automaton.constructor.model.data.MultiTapeTuringMachineData
import automaton.constructor.model.memory.MemoryUnitDescriptor
import automaton.constructor.model.memory.tape.MultiTrackTapeDescriptor
import automaton.constructor.utils.I18N

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package automaton.constructor.model.automaton

import automaton.constructor.model.automaton.flavours.AutomatonWithTracks
import automaton.constructor.model.data.MultiTrackTuringMachineData
import automaton.constructor.model.memory.MemoryUnitDescriptor
import automaton.constructor.model.memory.tape.MultiTrackTapeDescriptor
import automaton.constructor.utils.I18N

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import automaton.constructor.model.action.transition.EliminateEpsilonTransitionA
import automaton.constructor.model.automaton.flavours.AutomatonWithInputTape
import automaton.constructor.model.automaton.flavours.AutomatonWithStacks
import automaton.constructor.model.data.PushdownAutomatonData
import automaton.constructor.model.memory.MemoryUnitDescriptor
import automaton.constructor.model.memory.StackDescriptor
import automaton.constructor.model.memory.tape.InputTapeDescriptor
import automaton.constructor.utils.I18N
Expand Down
9 changes: 9 additions & 0 deletions src/main/kotlin/automaton/constructor/model/memory/Test.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package automaton.constructor.model.memory

import automaton.constructor.model.data.MemoryUnitDescriptorData
import kotlinx.serialization.Serializable

data class Test(val input: List<MemoryUnitDescriptor>)

@Serializable
data class TestsForSerializing(val tests: List<List<MemoryUnitDescriptorData>>, val automatonType: String)
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import java.text.MessageFormat

class MultiTrackTapeDescriptor(val trackCount: Int) : MemoryUnitDescriptor {
val valueProperties = List(trackCount) { "".toProperty() }
constructor(trackCount: Int, initValues: List<String>) : this(trackCount) {
valueProperties.zip(initValues).forEach { (a, b) -> a.value = b }
constructor(newTrackCount: Int, initialValues: List<String>) : this(newTrackCount) {
valueProperties.zip(initialValues).forEach { (a, b) -> a.value = b }
}

val headMoveDirection =
Expand Down
47 changes: 47 additions & 0 deletions src/main/kotlin/automaton/constructor/utils/ExecutorUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package automaton.constructor.utils

import automaton.constructor.model.automaton.Automaton
import automaton.constructor.model.memory.MemoryUnit
import automaton.constructor.model.module.executor.ExecutionStatus
import automaton.constructor.model.module.executor.Executor
import automaton.constructor.model.module.problems
import automaton.constructor.view.module.executor.executionLeafView

data class ExecutorResult(
val executionResult: String,
val graphic: SettingGroupEditor?
)

fun getNewExecutorOrNull(automaton: Automaton): Executor? {
if (automaton.problems.isNotEmpty()) {
tornadofx.error(
I18N.messages.getString("ExecutorController.Error.ExecutionFailed"),
automaton.problems.joinToString("\n") { it.message },
title = I18N.messages.getString("Dialog.error")
)
return null
}
return Executor(automaton)
}

fun createExecutorAndRun(automaton: Automaton, memory: List<MemoryUnit>? = null): ExecutorResult? {
val executor = getNewExecutorOrNull(automaton)
if (executor == null) {
return null
}
if (memory == null) {
executor.start()
} else {
executor.start(memory)
}
executor.runFor()
val executionResult = when (executor.status) {
ExecutionStatus.ACCEPTED -> I18N.messages.getString("ExecutorController.Executor.Status.Accepted")
ExecutionStatus.REJECTED -> I18N.messages.getString("ExecutorController.Executor.Status.Rejected")
ExecutionStatus.FROZEN -> I18N.messages.getString("ExecutorController.Executor.Status.Frozen")
ExecutionStatus.RUNNING -> I18N.messages.getString("ExecutorController.Executor.Status.Running")
}
val graphic = executor.acceptedExeStates.firstOrNull()?.let { executionLeafView(it) }
automaton.clearExecutionStates()
return ExecutorResult(executionResult, graphic)
}
28 changes: 11 additions & 17 deletions src/main/kotlin/automaton/constructor/view/ExamplesView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,7 @@ import kotlin.io.path.Path
@Serializable
data class Example(val name: String, val description: String)

class ExampleCell(
private val counter: IntegerProperty,
private val automatonName: StringProperty
): ListCell<Example?>() {
class ExampleCell(private val automatonName: StringProperty): ListCell<Example?>() {
init {
this.setOnMouseClicked {
if (it.clickCount == 2 && this.item != null)
Expand All @@ -32,7 +29,6 @@ class ExampleCell(
override fun updateItem(item: Example?, empty: Boolean) {
super.updateItem(item, empty)
graphic = if (item != null) {
counter.set(counter.value + 1) // this whole counter thing obviously needs to be remade
Text().apply { text = I18N.automatonExamples.getString("ExamplesFragment.${item.name}") }
} else
null
Expand All @@ -52,22 +48,20 @@ class ExamplesView: View() {
val description = Text().apply { text = I18N.messages.getString("ExamplesFragment.Choose") }
val image = ImageView()
val descriptionVBox = VBox(description, image)
val counter = 0.toProperty()
val automatonName = "".toProperty()
minWidth = 800.0

add(descriptionVBox)
examplesListView.setCellFactory { ExampleCell(counter, automatonName) }
counter.addListener(ChangeListener { _, _, _ ->
val selectedCellIndex = examplesListView.selectionModel.selectedIndex
if (selectedCellIndex != -1) {
description.text =
I18N.automatonExamples.getString(
"ExamplesFragment.${examples[selectedCellIndex].name}Description")
image.image = Image(
"file:///${System.getProperty("user.dir")}/src/main/resources/examples/images/${examples[selectedCellIndex].name}.png",
true)
}

examplesListView.setCellFactory { ExampleCell(automatonName) }

examplesListView.selectionModel.selectedItemProperty().addListener(ChangeListener { _, _, newValue ->
description.text = I18N.automatonExamples.getString("ExamplesFragment.${newValue.name}Description")
image.image = Image(
"file:///${System.getProperty("user.dir")}/src/main/resources/examples/images/${newValue.name}.png",
true)
})

automatonName.addListener(ChangeListener { _, _, newValue ->
val automatonsPath = Path("${System.getProperty("user.dir")}/src/main/resources/examples/automatons")
Files.walk(automatonsPath).forEach {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package automaton.constructor.view

import automaton.constructor.controller.Test
import automaton.constructor.model.memory.Test
import automaton.constructor.utils.I18N
import automaton.constructor.utils.SettingGroup
import automaton.constructor.utils.SettingGroupEditor
Expand Down
Loading

0 comments on commit 7a4d9f4

Please sign in to comment.