Fix logic and relation operators precedence and enable lazy evaluation of logic's operators (and, or) operands
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user