From 7060afc57c6fa47b1fabf040ed31e6cccd081dd4 Mon Sep 17 00:00:00 2001 From: chiruvol Date: Tue, 22 Sep 2020 14:43:37 -0700 Subject: [PATCH] nested ternary --- core/src/main/antlr4/MetricExpression.g4 | 3 +- .../expressions/ExpressionParser.java | 12 ++- .../expressions/TestExpressionParser.java | 101 ++++++++++++++++++ 3 files changed, 114 insertions(+), 2 deletions(-) diff --git a/core/src/main/antlr4/MetricExpression.g4 b/core/src/main/antlr4/MetricExpression.g4 index d09d17891d..eb64a32a48 100644 --- a/core/src/main/antlr4/MetricExpression.g4 +++ b/core/src/main/antlr4/MetricExpression.g4 @@ -58,9 +58,10 @@ relationalop: '<'|'>'|'=='|'<='|'>='|'!='; ternaryExpression : '(' ternaryExpression ')' #paren_ternary_rule | (logicalExpression|relationalExpression|metric) '?' ternaryOperands ':' ternaryOperands #main_ternary_rule + | ternaryExpression '?' ternaryOperands ':' ternaryOperands #nested_ternary_rule ; -ternaryOperands: expression // We can label alternatives - but seems to me like the output will have a single type +ternaryOperands: expression ; diff --git a/core/src/main/java/net/opentsdb/query/processor/expressions/ExpressionParser.java b/core/src/main/java/net/opentsdb/query/processor/expressions/ExpressionParser.java index 4bb98578c7..fe5467f583 100644 --- a/core/src/main/java/net/opentsdb/query/processor/expressions/ExpressionParser.java +++ b/core/src/main/java/net/opentsdb/query/processor/expressions/ExpressionParser.java @@ -706,7 +706,17 @@ public Object visitTernary(TernaryContext ctx) { @Override public Object visitParen_ternary_rule(Paren_ternary_ruleContext ctx) { - return null; + ctx.getChild(0).accept(this); + ctx.getChild(2).accept(this); + return ctx.getChild(1).accept(this); + } + + @Override + public Object visitNested_ternary_rule(MetricExpressionParser.Nested_ternary_ruleContext ctx) { + Object condition = ctx.getChild(0).accept(this); + Object left = ctx.getChild(2).accept(this); + Object right = ctx.getChild(4).accept(this); + return newTernary(condition, left, right); } @Override diff --git a/core/src/test/java/net/opentsdb/query/processor/expressions/TestExpressionParser.java b/core/src/test/java/net/opentsdb/query/processor/expressions/TestExpressionParser.java index a91aa48449..975e8dbcee 100644 --- a/core/src/test/java/net/opentsdb/query/processor/expressions/TestExpressionParser.java +++ b/core/src/test/java/net/opentsdb/query/processor/expressions/TestExpressionParser.java @@ -734,6 +734,107 @@ public void ternary() throws Exception { //ExpressionParser parser = new ExpressionParser(config("a + 1 * c")); // TODO - allow "1 > a : b"? } + + @Test + public void nested_ternary() throws Exception { + ExpressionParser parser = new ExpressionParser(config("(a > b ? c : d)")); + List nodes = parser.parse(); + assertEquals(2, nodes.size()); + ExpressionParseNode node = nodes.get(0); + assertEquals("e1_SubExp#0", node.getId()); + assertEquals(OperandType.VARIABLE, node.getLeftType()); + assertEquals("a", node.getLeft()); + assertEquals(OperandType.VARIABLE, node.getRightType()); + assertEquals("b", node.getRight()); + assertEquals(ExpressionOp.GT, node.getOperator()); + + node = nodes.get(1); + assertEquals("e1", node.getId()); + assertEquals(OperandType.VARIABLE, node.getLeftType()); + assertEquals("c", node.getLeft()); + assertEquals(OperandType.VARIABLE, node.getRightType()); + assertEquals("d", node.getRight()); + assertNull(node.getOperator()); + assertEquals(OperandType.SUB_EXP, ((TernaryParseNode) node).getConditionType()); + assertEquals("e1_SubExp#0", ((TernaryParseNode) node).getCondition()); + + parser = new ExpressionParser(config("a <= 1 ?(a > m && j < l) : o + y >= 1.89 ? h : p")); + nodes = parser.parse(); + assertEquals(8, nodes.size()); + node = nodes.get(0); + assertEquals("e1_SubExp#0", node.getId()); + assertEquals(OperandType.VARIABLE, node.getLeftType()); + assertEquals("a", node.getLeft()); + assertEquals(OperandType.LITERAL_NUMERIC, node.getRightType()); + assertEquals(new NumericLiteral(1), node.getRight()); + assertEquals(ExpressionOp.LE, node.getOperator()); + + node = nodes.get(1); + assertEquals("e1_SubExp#1", node.getId()); + assertEquals(OperandType.VARIABLE, node.getLeftType()); + assertEquals("a", node.getLeft()); + assertEquals(OperandType.VARIABLE, node.getRightType()); + assertEquals("m", node.getRight()); + assertEquals(ExpressionOp.GT, node.getOperator()); + + node = nodes.get(2); + assertEquals("e1_SubExp#2", node.getId()); + assertEquals(OperandType.VARIABLE, node.getLeftType()); + assertEquals("j", node.getLeft()); + assertEquals(OperandType.VARIABLE, node.getRightType()); + assertEquals("l", node.getRight()); + assertEquals(ExpressionOp.LT, node.getOperator()); + + node = nodes.get(3); + assertEquals("e1_SubExp#3", node.getId()); + assertEquals(OperandType.SUB_EXP, node.getLeftType()); + assertEquals("e1_SubExp#1", node.getLeft()); + assertEquals(OperandType.SUB_EXP, node.getRightType()); + assertEquals("e1_SubExp#2", node.getRight()); + assertEquals(ExpressionOp.AND, node.getOperator()); + + node = nodes.get(4); + assertEquals("e1_SubExp#4", node.getId()); + assertEquals(OperandType.VARIABLE, node.getLeftType()); + assertEquals("o", node.getLeft()); + assertEquals(OperandType.VARIABLE, node.getRightType()); + assertEquals("y", node.getRight()); + assertEquals(ExpressionOp.ADD, node.getOperator()); + + node = nodes.get(5); + assertEquals("e1_SubExp#5", node.getId()); + assertEquals(OperandType.SUB_EXP, node.getLeftType()); + assertEquals("e1_SubExp#4", node.getLeft()); + assertEquals(OperandType.LITERAL_NUMERIC, node.getRightType()); + assertEquals(new NumericLiteral(1.89), node.getRight()); + assertEquals(ExpressionOp.GE, node.getOperator()); + + node = nodes.get(6); + + assertEquals("e1_TernaryExp#6", node.getId()); + assertEquals(OperandType.SUB_EXP, node.getLeftType()); + assertEquals("e1_SubExp#3", node.getLeft()); + assertEquals(OperandType.SUB_EXP, node.getRightType()); + assertEquals("e1_SubExp#5", node.getRight()); + assertEquals(OperandType.SUB_EXP, ((TernaryParseNode) node).getConditionType()); + assertEquals("e1_SubExp#0", ((TernaryParseNode) node).getCondition()); + + node = nodes.get(7); + + assertEquals("e1", node.getId()); + assertEquals(OperandType.VARIABLE, node.getLeftType()); + assertEquals("h", node.getLeft()); + assertEquals(OperandType.VARIABLE, node.getRightType()); + assertEquals("p", node.getRight()); + assertEquals(OperandType.SUB_EXP, ((TernaryParseNode) node).getConditionType()); + assertEquals("e1_TernaryExp#6", ((TernaryParseNode) node).getCondition()); + + //parser = new ExpressionParser(config("a <= 1 ?(a > m && j < l) : o + y >= 1.89 ? h : p")); + + //parser = new ExpressionParser(config("a <= 1 ?(a > m && j < l) : o + y >= 1.89 ? h : p : !(h > 1) && k < i ")); + + //parser = new ExpressionParser(config("(a + c) > 3 ? (a > m && j < l) ? o + y >= 1.89 : h > 4 ? p : k * l /i > 6 : i")); + } ExpressionConfig config(final String exp) { return (ExpressionConfig) ExpressionConfig.newBuilder()