internal class BooleanRewritingWalker : BabelParserBaseListener() { var isBooleanExpression = false private set override fun exitBooleanExpr(ctx: BooleanExprContext) { isBooleanExpression = true val operation = ctx.children?.firstOrNull { it.isOperation } when(operation){ is BabelParser.LteqContext -> { val childScalar = insertScalar(ctx) swapInequalityWithSubtraction(childScalar, "~<=") } is BabelParser.GteqContext -> { val childScalar = insertScalar(ctx) swapLiteralChildren(childScalar) swapInequalityWithSubtraction(childScalar, "~>=") } is BabelParser.LtContext -> { val childScalar = insertScalar(ctx) swapInequalityWithSubtraction(childScalar , "~<") addEpsilon(childScalar) } is BabelParser.GtContext ->{ val childScalar = insertScalar(ctx) swapLiteralChildren(childScalar) swapInequalityWithSubtraction(childScalar, "~>") addEpsilon(childScalar) } else ->{ //no-op for error nodes or re-written trees. } } } //signature implies purity, _but it absolutely is not pure_ private fun insertScalar(ctx: BooleanExprContext): ScalarExprContext { val originalChildren = ArrayList(ctx.children) ctx.children.clear() configure(ctx){ scalar(originalChildren) } return ctx.children.single() as ScalarExprContext } private fun addEpsilon(ctx: ScalarExprContext) { val originalChildren = ArrayList(ctx.children) ctx.children.clear() configure(ctx) { scalar(originalChildren) plus() scalar { literal(value = Epsilon) } } } private fun swapInequalityWithSubtraction(ctx: ScalarExprContext, replacedElement: String) { val originalChildren = ArrayList(ctx.children) ctx.children.clear() configure(ctx){ originalChildren.first() minus(text = replacedElement) originalChildren.last() } } private fun swapLiteralChildren(ctx: ScalarExprContext) { val firstChild = ctx.children.first() ctx.apply { children[0] = children[2] children[2] = firstChild } } private val ParseTree.isOperation get() = this.childCount == 1 && this.getChild(0) is TerminalNode companion object { @JvmField val Epsilon: Double = java.lang.Double.MIN_NORMAL } } class Rewriter(val target: ParserRuleContext) { fun plus(text: String = "+"){ val element = BabelParser.PlusContext(target, -1).apply { terminal = CommonToken(BabelLexer.PLUS, text) } target.children.add(element) } fun minus(text: String = "-"){ val element = BabelParser.MinusContext(target, -1).apply { terminal = CommonToken(BabelLexer.MINUS, text) } target.children.add(element) } fun literal(value: Double) { target.children.add(TerminalNodeImpl(ValueToken(value))) } fun scalar(initialChildren: List = mutableListOf(), block: Rewriter.() -> Unit = {}){ val scalarCtx = ScalarExprContext(target, -1).apply { children = initialChildren } Rewriter(scalarCtx).block() target.children.add(scalarCtx) } } fun configure(target: ParserRuleContext, block: Rewriter.() -> Unit) { Rewriter(target).block() }