Fix logic and relation operators precedence and enable lazy evaluation of logic's operators (and, or) operands

This commit is contained in:
2020-03-15 15:04:51 +01:00
parent a68dc4f873
commit cc9d101609
2 changed files with 29 additions and 33 deletions

View File

@@ -19,15 +19,15 @@ class SubexpressionParser : Parser() {
val expr2Parser = leftAssociativeOperator(
expr1Parser,
listOf(TokenType.AND),
listOf(TokenType.RELATION, TokenType.OPEN_ANGLE, TokenType.CLOSE_ANGLE),
assert(expr1Parser, "expression")
) { lhs, operator, rhs ->
LogicOperatorNode(lhs, operator, rhs)
RelationOperatorNode(lhs, operator, rhs)
}
val expr3Parser = leftAssociativeOperator(
expr2Parser,
listOf(TokenType.OR),
listOf(TokenType.AND),
assert(expr2Parser, "expression")
) { lhs, operator, rhs ->
LogicOperatorNode(lhs, operator, rhs)
@@ -35,10 +35,10 @@ class SubexpressionParser : Parser() {
val expr4Parser = leftAssociativeOperator(
expr3Parser,
listOf(TokenType.RELATION, TokenType.OPEN_ANGLE, TokenType.CLOSE_ANGLE),
listOf(TokenType.OR),
assert(expr3Parser, "expression")
) { lhs, operator, rhs ->
RelationOperatorNode(lhs, operator, rhs)
LogicOperatorNode(lhs, operator, rhs)
}
return expr4Parser.parse(input)

View File

@@ -14,41 +14,37 @@ import io.smnp.type.enumeration.DataType
import io.smnp.type.model.Value
class LogicOperatorEvaluator : Evaluator() {
private val evaluator = ExpressionEvaluator()
override fun supportedNodes() = listOf(LogicOperatorNode::class)
override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput {
val evaluator = ExpressionEvaluator()
val (lhsNode, opNode, rhsNode) = (node as LogicOperatorNode)
val lhs = evaluator.evaluate(lhsNode, environment).value
val rhs = evaluator.evaluate(rhsNode, environment).value
val operator = (opNode as TokenNode).token.type
if (lhs.type != DataType.BOOL) {
throw PositionException(
EnvironmentException(
EvaluationException("Operator '${operator.token}' supports only bool types"),
environment
),
lhsNode.position
)
}
if (rhs.type != DataType.BOOL) {
throw PositionException(
EnvironmentException(
EvaluationException("Operator '${operator.token}' supports only bool types"),
environment
),
rhsNode.position
)
}
return EvaluatorOutput.value(
when (operator) {
TokenType.AND -> Value.bool((lhs.value as Boolean) && (rhs.value as Boolean))
TokenType.OR -> Value.bool((lhs.value as Boolean) || (rhs.value as Boolean))
else -> throw ShouldNeverReachThisLineException()
}
Value.bool(
when (operator) {
TokenType.AND -> if(evalOperand(lhsNode, operator, environment)) evalOperand(rhsNode, operator, environment) else false
TokenType.OR -> if (evalOperand(lhsNode, operator, environment)) true else evalOperand(rhsNode, operator, environment)
else -> throw ShouldNeverReachThisLineException()
}
)
)
}
private fun evalOperand(operand: Node, operator: TokenType, environment: Environment): Boolean {
val value = evaluator.evaluate(operand, environment).value
if (value.type != DataType.BOOL) {
throw PositionException(
EnvironmentException(
EvaluationException("Operator '${operator.token}' supports only bool types, found ${value.typeName}"),
environment
),
operand.position
)
}
return value.value as Boolean
}
}