From 2693f0530a5c4f753d0ff9fee6f50f849fe2d6a9 Mon Sep 17 00:00:00 2001 From: Carson-McCombs Date: Wed, 26 Jun 2024 13:58:51 -0500 Subject: [PATCH] Fixed an issue with the Parser where if the token at the top of the operator stack is a parenthesis, that it would attempt to convert it into a function and crash. --- .../parser/evaluator/ShuntingYardParser.kt | 10 ++--- .../expressionGroupScreen/ErrorPopupView.kt | 24 +++++++++++ .../expressionGroupScreen/GroupScreenView.kt | 4 +- .../java/viewModel/GroupScreenViewModel.kt | 41 +++++++++++-------- 4 files changed, 55 insertions(+), 24 deletions(-) create mode 100644 app/src/main/java/view/expressionGroupScreen/ErrorPopupView.kt diff --git a/app/src/main/java/model/parser/evaluator/ShuntingYardParser.kt b/app/src/main/java/model/parser/evaluator/ShuntingYardParser.kt index eda4402..c654a15 100644 --- a/app/src/main/java/model/parser/evaluator/ShuntingYardParser.kt +++ b/app/src/main/java/model/parser/evaluator/ShuntingYardParser.kt @@ -96,6 +96,7 @@ class ShuntingYardParser { val baseParseResult = ParseResult(isStatic = isStatic, globalDependencyIds = globalDependencyIds, localDependencyIds = localDependencyIds) val outputQueue = ArrayDeque() val operatorStack = ArrayDeque() + //println(tokens.joinToString ("\n ")) for (token in tokens) { //println("-------------") //println("Token: ${token.text}") @@ -117,7 +118,6 @@ class ShuntingYardParser { while (operatorStack.first().text != "(") { if (operatorStack.isEmpty()) return baseParseResult.copy( errorText = "No opening parenthesis found") - //outputQueue.addLast(operatorStack.removeFirst()) //println("-------------") //println("Token: ${operatorStack.first().text}") //println("Output Queue: ${outputQueue.map { t -> t.text }}") @@ -138,12 +138,13 @@ class ShuntingYardParser { operatorStack.addFirst(token) continue } - //var functionA = Function.functionMap[token.text] ?: return Pair(null, Error("Unknown Function \"${operatorStack.first()}\"")) - //var functionB = Function.functionMap[operatorStack.first().text] ?: return Pair(null, Error("Unknown Function \"${operatorStack.first()}\"")) + if (operatorStack.first().tokenType == TokenType.PUNCTUATION){ + operatorStack.addFirst(token) + continue + } val tokenFunction = token.value as Function var otherFunction = operatorStack.first().value as Function while ((otherFunction.name != "(") && (tokenFunction.precedence > otherFunction.precedence) || (tokenFunction.precedence == otherFunction.precedence && tokenFunction.associativity == AssociativityDirection.LeftToRight)) { - //outputQueue.addLast(operatorStack.removeFirst()) //println("-------------") //println("Token: ${operatorStack.first().text}") //println("Output Queue: ${outputQueue.map { t -> t.text }}") @@ -164,7 +165,6 @@ class ShuntingYardParser { //println("Output Queue: ${outputQueue.map { t -> t.text }}") //println("Operator Stack: ${operatorStack.map { t -> t.text }}") if (operatorStack.last().text == "(") return baseParseResult.copy( errorText = "Cannot end statement with an open parenthesis") - //outputQueue.addLast(operatorStack.removeFirst()) val err = addToOutputQueue(outputQueue, operatorStack.removeFirst()) if (err != null) return baseParseResult.copy( errorText = err.message ?: "") } diff --git a/app/src/main/java/view/expressionGroupScreen/ErrorPopupView.kt b/app/src/main/java/view/expressionGroupScreen/ErrorPopupView.kt new file mode 100644 index 0000000..bf74b0d --- /dev/null +++ b/app/src/main/java/view/expressionGroupScreen/ErrorPopupView.kt @@ -0,0 +1,24 @@ +package view.expressionGroupScreen + +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.window.Popup + +@Composable +fun ErrorPopupView(title: String, error: Error){ + Popup { + Text( + text = title, + style = MaterialTheme.typography.titleLarge + ) + Text(text = error.message ?: "empty error message") + } +} + +@Preview +@Composable +fun ErrorPopupView_Preview(){ + ErrorPopupView(title = "Error Preview", error = Error("Example Error Text")) +} \ No newline at end of file diff --git a/app/src/main/java/view/expressionGroupScreen/GroupScreenView.kt b/app/src/main/java/view/expressionGroupScreen/GroupScreenView.kt index 4fbb9b0..14802eb 100644 --- a/app/src/main/java/view/expressionGroupScreen/GroupScreenView.kt +++ b/app/src/main/java/view/expressionGroupScreen/GroupScreenView.kt @@ -72,7 +72,7 @@ fun GroupScreenView( addChildGroup = { viewModel.addChildExpressionGroup() }, expressionEvents = remember(viewModel.id, "expressionEvents") { ExpressionEvents.fromViewModel(viewModel)}, groupEvents = remember(viewModel.id, "expressionEvents") { GroupEvents.fromViewModel(viewModel) }, - groupScreenEvents = groupScreenEvents + groupScreenEvents = groupScreenEvents, ) } @@ -89,7 +89,7 @@ private fun GroupScreenView( addChildGroup: () -> Unit, expressionEvents: ExpressionEvents, groupEvents: GroupEvents, - groupScreenEvents: GroupScreenEvents + groupScreenEvents: GroupScreenEvents, ){ Scaffold( diff --git a/app/src/main/java/viewModel/GroupScreenViewModel.kt b/app/src/main/java/viewModel/GroupScreenViewModel.kt index 163e89b..d10d71c 100644 --- a/app/src/main/java/viewModel/GroupScreenViewModel.kt +++ b/app/src/main/java/viewModel/GroupScreenViewModel.kt @@ -75,6 +75,8 @@ class GroupScreenViewModel( initialValue = emptyMap() ) + val unhandledErrorState: Pair? = null + private val _expressionTextFieldStateMap: MutableMap = mutableMapOf() fun getExpressionTextFieldState(expressionId: Long): TextFieldState { @@ -188,23 +190,28 @@ class GroupScreenViewModel( val name = getExpressionNameTextFieldState(expressionId).text.toString() val rawText = getExpressionTextFieldState(expressionId).text.toString() var expression = childExpressionsMap.value[expressionId]!! - val parseResult = ShuntingYardParser.evaluate( - id = expressionId, - rawText = rawText, - getGroupPath = { exprId -> - repository.getExpressionGroupPath(exprId) - }, - getExpressionId = { expressionFullPath: String -> - repository.expressionFullPathToIdMap.value[expressionFullPath] - }, - getExpression = { exprId: Long -> - repository.expressionMap.value[exprId] - }, - getOverlappingDependencies = {exprId, otherIds -> repository.getOverlappingDependencies(exprId, otherIds) } - ) - expression = expression.copy(name = name, text = rawText, parseResult = parseResult, updated = true) - repository.upsertExpression(expression) - if (oldText != rawText) repository.updateDependentExpressions(expression = expression) + try { + val parseResult = ShuntingYardParser.evaluate( + id = expressionId, + rawText = rawText, + getGroupPath = { exprId -> + repository.getExpressionGroupPath(exprId) + }, + getExpressionId = { expressionFullPath: String -> + repository.expressionFullPathToIdMap.value[expressionFullPath] + }, + getExpression = { exprId: Long -> + repository.expressionMap.value[exprId] + }, + getOverlappingDependencies = {exprId, otherIds -> repository.getOverlappingDependencies(exprId, otherIds) } + ) + expression = expression.copy(name = name, text = rawText, parseResult = parseResult, updated = true) + repository.upsertExpression(expression) + if (oldText != rawText) repository.updateDependentExpressions(expression = expression) + } catch (error: Error) { + println(error) + } + } }