/* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch licenses this file to you under * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.elasticsearch.painless.node; import org.elasticsearch.painless.CompilerSettings; import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition.Cast; import org.elasticsearch.painless.Definition.Field; import org.elasticsearch.painless.Definition.Method; import org.elasticsearch.painless.Definition.MethodKey; import org.elasticsearch.painless.Definition.RuntimeClass; import org.elasticsearch.painless.Definition.Struct; import org.elasticsearch.painless.FeatureTest; import org.elasticsearch.painless.GenericElasticsearchScript; import org.elasticsearch.painless.Locals.Variable; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.ScriptInterface; import org.elasticsearch.painless.Operation; import org.elasticsearch.painless.antlr.Walker; import org.elasticsearch.test.ESTestCase; import java.util.Arrays; import java.util.List; import java.util.Map; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; /** * Tests {@link Object#toString} implementations on all extensions of {@link ANode}. */ public class NodeToStringTests extends ESTestCase { private final Definition definition = Definition.BUILTINS; public void testEAssignment() { assertToString( "(SSource\n" + " (SDeclBlock (SDeclaration def i))\n" + " (SExpression (EAssignment (EVariable i) = (ENumeric 2)))\n" + " (SReturn (EVariable i)))", "def i;\n" + "i = 2;\n" + "return i"); for (String operator : new String[] {"+", "-", "*", "/", "%", "&", "^", "|", "<<", ">>", ">>>"}) { assertToString( "(SSource\n" + " (SDeclBlock (SDeclaration def i (ENumeric 1)))\n" + " (SExpression (EAssignment (EVariable i) " + operator + "= (ENumeric 2)))\n" + " (SReturn (EVariable i)))", "def i = 1;\n" + "i " + operator + "= 2;\n" + "return i"); } // Compound assertToString( "(SSource\n" + " (SDeclBlock (SDeclaration def i))\n" + " (SReturn (EAssignment (EVariable i) = (ENumeric 2))))", "def i;\n" + "return i = 2"); assertToString( "(SSource\n" + " (SDeclBlock (SDeclaration def i))\n" + " (SReturn (EAssignment (EVariable i) ++ post)))", "def i;\n" + "return i++"); assertToString( "(SSource\n" + " (SDeclBlock (SDeclaration def i))\n" + " (SReturn (EAssignment (EVariable i) ++ pre)))", "def i;\n" + "return ++i"); assertToString( "(SSource\n" + " (SDeclBlock (SDeclaration def i))\n" + " (SReturn (EAssignment (EVariable i) -- post)))", "def i;\n" + "return i--"); assertToString( "(SSource\n" + " (SDeclBlock (SDeclaration def i))\n" + " (SReturn (EAssignment (EVariable i) -- pre)))", "def i;\n" + "return --i"); } public void testEBinary() { assertToString( "(SSource (SReturn (EBinary (ENumeric 1) * (ENumeric 1))))", "return 1 * 1"); assertToString( "(SSource (SReturn (EBinary (ENumeric 1) / (ENumeric 1))))", "return 1 / 1"); assertToString( "(SSource (SReturn (EBinary (ENumeric 1) % (ENumeric 1))))", "return 1 % 1"); assertToString( "(SSource (SReturn (EBinary (ENumeric 1) + (ENumeric 1))))", "return 1 + 1"); assertToString( "(SSource (SReturn (EBinary (ENumeric 1) - (ENumeric 1))))", "return 1 - 1"); assertToString( "(SSource (SReturn (EBinary (EString 'asb') =~ (ERegex /cat/))))", "return 'asb' =~ /cat/"); assertToString("(SSource (SReturn (EBinary (EString 'asb') ==~ (ERegex /cat/))))", "return 'asb' ==~ /cat/"); assertToString( "(SSource (SReturn (EBinary (ENumeric 1) << (ENumeric 1))))", "return 1 << 1"); assertToString( "(SSource (SReturn (EBinary (ENumeric 1) >> (ENumeric 1))))", "return 1 >> 1"); assertToString( "(SSource (SReturn (EBinary (ENumeric 1) >>> (ENumeric 1))))", "return 1 >>> 1"); assertToString( "(SSource (SReturn (EBinary (ENumeric 1) & (ENumeric 1))))", "return 1 & 1"); assertToString( "(SSource (SReturn (EBinary (ENumeric 1) ^ (ENumeric 1))))", "return 1 ^ 1"); assertToString( "(SSource (SReturn (EBinary (ENumeric 1) | (ENumeric 1))))", "return 1 | 1"); } public void testEBool() { assertToString("(SSource (SReturn (EBool (EBoolean true) && (EBoolean false))))", "return true && false"); assertToString("(SSource (SReturn (EBool (EBoolean true) || (EBoolean false))))", "return true || false"); } public void testEBoolean() { assertToString("(SSource (SReturn (EBoolean true)))", "return true"); assertToString("(SSource (SReturn (EBoolean false)))", "return false"); } public void testECallLocal() { assertToString( "(SSource\n" + " (SFunction def a\n" + " (SReturn (EBoolean true)))\n" + " (SReturn (ECallLocal a)))", "def a() {\n" + " return true\n" + "}\n" + "return a()"); assertToString( "(SSource\n" + " (SFunction def a (Args (Pair int i) (Pair int j))\n" + " (SReturn (EBoolean true)))\n" + " (SReturn (ECallLocal a (Args (ENumeric 1) (ENumeric 2)))))", "def a(int i, int j) {\n" + " return true\n" + "}\n" + "return a(1, 2)"); } public void testECapturingFunctionRef() { assertToString( "(SSource\n" + " (SDeclBlock (SDeclaration Integer x (PCallInvoke (EStatic Integer) valueOf (Args (ENumeric 5)))))\n" + " (SReturn (PCallInvoke (PCallInvoke (EStatic Optional) empty) orElseGet (Args (ECapturingFunctionRef x toString)))))", "Integer x = Integer.valueOf(5);\n" + "return Optional.empty().orElseGet(x::toString)"); } public void testECast() { Location l = new Location(getTestName(), 0); AExpression child = new EConstant(l, "test"); Cast cast = new Cast(Definition.STRING_TYPE, Definition.INT_OBJ_TYPE, true); assertEquals("(ECast Integer (EConstant String 'test'))", new ECast(l, child, cast).toString()); l = new Location(getTestName(), 1); child = new EBinary(l, Operation.ADD, new EConstant(l, "test"), new EConstant(l, 12)); cast = new Cast(Definition.INT_OBJ_TYPE, Definition.BOOLEAN_OBJ_TYPE, true); assertEquals("(ECast Boolean (EBinary (EConstant String 'test') + (EConstant Integer 12)))", new ECast(l, child, cast).toString()); } public void testEComp() { assertToString( "(SSource (SReturn (EComp (PField (EVariable params) a) < (ENumeric 10))))", "return params.a < 10"); assertToString( "(SSource (SReturn (EComp (PField (EVariable params) a) <= (ENumeric 10))))", "return params.a <= 10"); assertToString( "(SSource (SReturn (EComp (PField (EVariable params) a) > (ENumeric 10))))", "return params.a > 10"); assertToString( "(SSource (SReturn (EComp (PField (EVariable params) a) >= (ENumeric 10))))", "return params.a >= 10"); assertToString( "(SSource (SReturn (EComp (PField (EVariable params) a) == (ENumeric 10))))", "return params.a == 10"); assertToString("(SSource (SReturn (EComp (PField (EVariable params) a) === (ENumeric 10))))", "return params.a === 10"); assertToString( "(SSource (SReturn (EComp (PField (EVariable params) a) != (ENumeric 10))))", "return params.a != 10"); assertToString("(SSource (SReturn (EComp (PField (EVariable params) a) !== (ENumeric 10))))", "return params.a !== 10"); } public void testEConditional() { assertToString("(SSource (SReturn (EConditional (PField (EVariable params) a) (ENumeric 1) (ENumeric 6))))", "return params.a ? 1 : 6"); } public void testEConstant() { assertEquals("(EConstant String '121')", new EConstant(new Location(getTestName(), 0), "121").toString()); assertEquals("(EConstant String '92 ')", new EConstant(new Location(getTestName(), 0), "92 ").toString()); assertEquals("(EConstant Integer 1237)", new EConstant(new Location(getTestName(), 1), 1237).toString()); assertEquals("(EConstant Boolean true)", new EConstant(new Location(getTestName(), 2), true).toString()); } public void testEDecimal() { assertToString("(SSource (SReturn (EDecimal 1.0)))", "return 1.0"); assertToString("(SSource (SReturn (EDecimal 14.121d)))", "return 14.121d"); assertToString("(SSource (SReturn (EDecimal 2234.1f)))", "return 2234.1f"); assertToString("(SSource (SReturn (EDecimal 14.121D)))", "return 14.121D"); assertToString("(SSource (SReturn (EDecimal 1234.1F)))", "return 1234.1F"); } public void testEElvis() { assertToString("(SSource (SReturn (EElvis (PField (EVariable params) a) (ENumeric 1))))", "return params.a ?: 1"); } public void testEExplicit() { assertToString("(SSource (SReturn (EExplicit byte (PField (EVariable params) a))))", "return (byte)(params.a)"); } public void testEFunctionRef() { assertToString( "(SSource (SReturn " + "(PCallInvoke (PCallInvoke (EStatic Optional) empty) orElseGet (Args (EFunctionRef Optional empty)))))", "return Optional.empty().orElseGet(Optional::empty)"); } public void testEInstanceOf() { assertToString("(SSource (SReturn (EInstanceof (ENewObj Object) Object)))", "return new Object() instanceof Object"); assertToString("(SSource (SReturn (EInstanceof (ENumeric 12) double)))", "return 12 instanceof double"); } public void testELambda() { assertToString( "(SSource (SReturn (PCallInvoke (PCallInvoke (EStatic Optional) empty) orElseGet (Args " + "(ELambda (SReturn (ENumeric 1)))))))", "return Optional.empty().orElseGet(() -> {\n" + " return 1\n" + "})"); assertToString( "(SSource (SReturn (PCallInvoke (PCallInvoke (EStatic Optional) empty) orElseGet (Args " + "(ELambda (SReturn (ENumeric 1)))))))", "return Optional.empty().orElseGet(() -> 1)"); assertToString( "(SSource (SReturn (PCallInvoke (PCallInvoke (PCallInvoke (EListInit (ENumeric 1) (ENumeric 2) (ENumeric 3)) stream) " + "mapToInt (Args (ELambda (Pair def x)\n" + " (SReturn (EBinary (EVariable x) + (ENumeric 1)))))) sum)))", "return [1, 2, 3].stream().mapToInt((def x) -> {\n" + " return x + 1\n" + "}).sum()"); assertToString( "(SSource (SReturn (PCallInvoke (PCallInvoke (PCallInvoke (EListInit (ENumeric 1) (ENumeric 2) (ENumeric 3)) stream) " + "mapToInt (Args (ELambda (Pair null x)\n" + " (SReturn (EBinary (EVariable x) + (ENumeric 1)))))) sum)))", "return [1, 2, 3].stream().mapToInt(x -> x + 1).sum()"); assertToString( "(SSource (SReturn (PCallInvoke (EListInit (EString 'a') (EString 'b')) sort (Args (ELambda (Pair def a) (Pair def b)\n" + " (SReturn (EBinary (PCallInvoke (EVariable a) length) - (PCallInvoke (EVariable b) length))))))))", "return ['a', 'b'].sort((def a, def b) -> {\n" + " return a.length() - b.length()\n" + "})"); assertToString( "(SSource (SReturn (PCallInvoke (EListInit (EString 'a') (EString 'b')) sort (Args (ELambda (Pair null a) (Pair null b)\n" + " (SReturn (EBinary (PCallInvoke (EVariable a) length) - (PCallInvoke (EVariable b) length))))))))", "return ['a', 'b'].sort((a, b) -> a.length() - b.length())"); assertToString( "(SSource (SReturn (PCallInvoke (EListInit (EString 'a') (EString 'b')) sort (Args (ELambda (Pair def a) (Pair def b)\n" + " (SIf (EComp (EVariable a) < (EVariable b)) (SBlock " + "(SReturn (EBinary (PCallInvoke (EVariable a) length) - (PCallInvoke (EVariable b) length)))))\n" + " (SReturn (ENumeric 1)))))))", "return ['a', 'b'].sort((def a, def b) -> {\n" + " if (a < b) {\n" + " return a.length() - b.length()\n" + " }\n" + " return 1\n" + "})"); } public void testEListInit() { assertToString("(SSource (SReturn (EListInit (ENumeric 1) (ENumeric 2) (EString 'cat') (EString 'dog') (ENewObj Object))))", "return [1, 2, 'cat', 'dog', new Object()]"); assertToString("(SSource (SReturn (EListInit)))", "return []"); } public void testEMapInit() { assertToString("(SSource (SReturn (EMapInit " + "(Pair (EString 'a') (ENumeric 1)) " + "(Pair (EString 'b') (ENumeric 3)) " + "(Pair (ENumeric 12) (ENewObj Object)))))", "return ['a': 1, 'b': 3, 12: new Object()]"); assertToString("(SSource (SReturn (EMapInit)))", "return [:]"); } public void testENewArray() { assertToString("(SSource (SReturn (ENewArray int dims (Args (ENumeric 10)))))", "return new int[10]"); assertToString("(SSource (SReturn (ENewArray int dims (Args (ENumeric 10) (ENumeric 4) (ENumeric 5)))))", "return new int[10][4][5]"); assertToString("(SSource (SReturn (ENewArray int init (Args (ENumeric 1) (ENumeric 2) (ENumeric 3)))))", "return new int[] {1, 2, 3}"); assertToString("(SSource (SReturn (ENewArray def init (Args (ENumeric 1) (ENumeric 2) (EString 'bird')))))", "return new def[] {1, 2, 'bird'}"); } public void testENewObj() { assertToString("(SSource (SReturn (ENewObj Object)))", "return new Object()"); assertToString("(SSource (SReturn (ENewObj DateTimeException (Args (EString 'test')))))", "return new DateTimeException('test')"); } public void testENull() { assertToString("(SSource (SReturn (ENull)))", "return null"); } public void testENumeric() { assertToString("(SSource (SReturn (ENumeric 1)))", "return 1"); assertToString("(SSource (SReturn (ENumeric 114121d)))", "return 114121d"); assertToString("(SSource (SReturn (ENumeric 114134f)))", "return 114134f"); assertToString("(SSource (SReturn (ENumeric 114121D)))", "return 114121D"); assertToString("(SSource (SReturn (ENumeric 111234F)))", "return 111234F"); assertToString("(SSource (SReturn (ENumeric 774121l)))", "return 774121l"); assertToString("(SSource (SReturn (ENumeric 881234L)))", "return 881234L"); assertToString("(SSource (SReturn (ENumeric 1 16)))", "return 0x1"); assertToString("(SSource (SReturn (ENumeric 774121l 16)))", "return 0x774121l"); assertToString("(SSource (SReturn (ENumeric 881234L 16)))", "return 0x881234L"); assertToString("(SSource (SReturn (ENumeric 1 8)))", "return 01"); assertToString("(SSource (SReturn (ENumeric 774121l 8)))", "return 0774121l"); assertToString("(SSource (SReturn (ENumeric 441234L 8)))", "return 0441234L"); } public void testERegex() { assertToString("(SSource (SReturn (ERegex /foo/)))", "return /foo/"); assertToString("(SSource (SReturn (ERegex /foo/ cix)))", "return /foo/cix"); assertToString("(SSource (SReturn (ERegex /foo/ cix)))", "return /foo/xci"); } public void testEStatic() { assertToString("(SSource (SReturn (PCallInvoke (EStatic Optional) empty)))", "return Optional.empty()"); } public void testEString() { assertToString("(SSource (SReturn (EString 'foo')))", "return 'foo'"); assertToString("(SSource (SReturn (EString ' oo')))", "return ' oo'"); assertToString("(SSource (SReturn (EString 'fo ')))", "return 'fo '"); assertToString("(SSource (SReturn (EString ' o ')))", "return ' o '"); } public void testEUnary() { assertToString("(SSource (SReturn (EUnary ! (EBoolean true))))", "return !true"); assertToString("(SSource (SReturn (EUnary ~ (ENumeric 1))))", "return ~1"); assertToString("(SSource (SReturn (EUnary + (ENumeric 1))))", "return +1"); assertToString("(SSource (SReturn (EUnary - (ENumeric 1))))", "return -(1)"); } public void testEVariable() { assertToString("(SSource (SReturn (EVariable params)))", "return params"); assertToString( "(SSource\n" + " (SDeclBlock (SDeclaration def a (ENumeric 1)))\n" + " (SReturn (EVariable a)))", "def a = 1;\n" + "return a"); } public void testPBrace() { assertToString("(SSource (SReturn (PBrace (PField (EVariable params) a) (ENumeric 10))))", "return params.a[10]"); assertToString("(SSource (SReturn (PBrace (EVariable params) (EString 'a'))))", "return params['a']"); } public void testPCallInvoke() { assertToString("(SSource (SReturn (PCallInvoke (EStatic Optional) empty)))", "return Optional.empty()"); assertToString("(SSource (SReturn (PCallInvoke (EStatic Optional) of (Args (ENumeric 1)))))", "return Optional.of(1)"); assertToString("(SSource (SReturn (PCallInvoke (EStatic Objects) equals (Args (ENumeric 1) (ENumeric 2)))))", "return Objects.equals(1, 2)"); assertToString("(SSource (SReturn (PCallInvoke (EVariable params) equals (Args (ENumeric 1)))))", "return params.equals(1)"); } public void testPField() { assertToString("(SSource (SReturn (PField (EVariable params) a)))", "return params.a"); assertToString("(SSource (SReturn (PField nullSafe (EVariable params) a)))", "return params?.a"); assertToString( "(SSource\n" + " (SDeclBlock (SDeclaration int[] a (ENewArray int dims (Args (ENumeric 10)))))\n" + " (SReturn (PField (EVariable a) length)))", "int[] a = new int[10];\n" + "return a.length"); assertToString( "(SSource\n" + " (SDeclBlock (SDeclaration org.elasticsearch.painless.FeatureTest a (ENewObj org.elasticsearch.painless.FeatureTest)))\n" + " (SExpression (EAssignment (PField (EVariable a) x) = (ENumeric 10)))\n" + " (SReturn (PField (EVariable a) x)))", "org.elasticsearch.painless.FeatureTest a = new org.elasticsearch.painless.FeatureTest();\n" + "a.x = 10;\n" + "return a.x"); } public void testPSubArrayLength() { Location l = new Location(getTestName(), 0); PSubArrayLength node = new PSubArrayLength(l, "int", "a"); node.prefix = new EVariable(l, "a"); assertEquals("(PSubArrayLength (EVariable a))", node.toString()); assertEquals("(PSubNullSafeField (PSubArrayLength (EVariable a)))", new PSubNullSafeField(l, node).toString()); } public void testPSubBrace() { Location l = new Location(getTestName(), 0); PSubBrace node = new PSubBrace(l, Definition.INT_TYPE, new ENumeric(l, "1", 10)); node.prefix = new EVariable(l, "a"); assertEquals("(PSubBrace (EVariable a) (ENumeric 1))", node.toString()); } public void testPSubCallInvoke() { Location l = new Location(getTestName(), 0); RuntimeClass c = definition.getRuntimeClass(Integer.class); Method m = c.methods.get(new MethodKey("toString", 0)); PSubCallInvoke node = new PSubCallInvoke(l, m, null, emptyList()); node.prefix = new EVariable(l, "a"); assertEquals("(PSubCallInvoke (EVariable a) toString)", node.toString()); assertEquals("(PSubNullSafeCallInvoke (PSubCallInvoke (EVariable a) toString))", new PSubNullSafeCallInvoke(l, node).toString()); l = new Location(getTestName(), 1); m = c.methods.get(new MethodKey("equals", 1)); node = new PSubCallInvoke(l, m, null, singletonList(new EVariable(l, "b"))); node.prefix = new EVariable(l, "a"); assertEquals("(PSubCallInvoke (EVariable a) equals (Args (EVariable b)))", node.toString()); assertEquals("(PSubNullSafeCallInvoke (PSubCallInvoke (EVariable a) equals (Args (EVariable b))))", new PSubNullSafeCallInvoke(l, node).toString()); } public void testPSubDefArray() { Location l = new Location(getTestName(), 0); PSubDefArray node = new PSubDefArray(l, new EConstant(l, 1)); node.prefix = new EVariable(l, "a"); assertEquals("(PSubDefArray (EVariable a) (EConstant Integer 1))", node.toString()); } public void testPSubDefCall() { Location l = new Location(getTestName(), 0); PSubDefCall node = new PSubDefCall(l, "toString", emptyList()); node.prefix = new EVariable(l, "a"); assertEquals("(PSubDefCall (EVariable a) toString)", node.toString()); assertEquals("(PSubNullSafeCallInvoke (PSubDefCall (EVariable a) toString))", new PSubNullSafeCallInvoke(l, node).toString()); l = new Location(getTestName(), 0); node = new PSubDefCall(l, "equals", singletonList(new EVariable(l, "b"))); node.prefix = new EVariable(l, "a"); assertEquals("(PSubDefCall (EVariable a) equals (Args (EVariable b)))", node.toString()); assertEquals("(PSubNullSafeCallInvoke (PSubDefCall (EVariable a) equals (Args (EVariable b))))", new PSubNullSafeCallInvoke(l, node).toString()); l = new Location(getTestName(), 0); node = new PSubDefCall(l, "superWeird", Arrays.asList(new EVariable(l, "b"), new EVariable(l, "c"), new EVariable(l, "d"))); node.prefix = new EVariable(l, "a"); assertEquals("(PSubDefCall (EVariable a) superWeird (Args (EVariable b) (EVariable c) (EVariable d)))", node.toString()); assertEquals("(PSubNullSafeCallInvoke (PSubDefCall (EVariable a) superWeird (Args (EVariable b) (EVariable c) (EVariable d))))", new PSubNullSafeCallInvoke(l, node).toString()); } public void testPSubDefField() { Location l = new Location(getTestName(), 0); PSubDefField node = new PSubDefField(l, "ok"); node.prefix = new EVariable(l, "a"); assertEquals("(PSubDefField (EVariable a) ok)", node.toString()); assertEquals("(PSubNullSafeCallInvoke (PSubDefField (EVariable a) ok))", new PSubNullSafeCallInvoke(l, node).toString()); } public void testPSubField() { Location l = new Location(getTestName(), 0); Struct s = definition.getType(Boolean.class.getSimpleName()).struct; Field f = s.staticMembers.get("TRUE"); PSubField node = new PSubField(l, f); node.prefix = new EStatic(l, "Boolean"); assertEquals("(PSubField (EStatic Boolean) TRUE)", node.toString()); assertEquals("(PSubNullSafeCallInvoke (PSubField (EStatic Boolean) TRUE))", new PSubNullSafeCallInvoke(l, node).toString()); } public void testPSubListShortcut() { Location l = new Location(getTestName(), 0); Struct s = definition.getType(List.class.getSimpleName()).struct; PSubListShortcut node = new PSubListShortcut(l, s, new EConstant(l, 1)); node.prefix = new EVariable(l, "a"); assertEquals("(PSubListShortcut (EVariable a) (EConstant Integer 1))", node.toString()); assertEquals("(PSubNullSafeCallInvoke (PSubListShortcut (EVariable a) (EConstant Integer 1)))", new PSubNullSafeCallInvoke(l, node).toString()); l = new Location(getTestName(), 0); s = definition.getType(List.class.getSimpleName()).struct; node = new PSubListShortcut(l, s, new EBinary(l, Operation.ADD, new EConstant(l, 1), new EConstant(l, 4))); node.prefix = new EVariable(l, "a"); assertEquals("(PSubListShortcut (EVariable a) (EBinary (EConstant Integer 1) + (EConstant Integer 4)))", node.toString()); } public void testPSubMapShortcut() { Location l = new Location(getTestName(), 0); Struct s = definition.getType(Map.class.getSimpleName()).struct; PSubMapShortcut node = new PSubMapShortcut(l, s, new EConstant(l, "cat")); node.prefix = new EVariable(l, "a"); assertEquals("(PSubMapShortcut (EVariable a) (EConstant String 'cat'))", node.toString()); assertEquals("(PSubNullSafeCallInvoke (PSubMapShortcut (EVariable a) (EConstant String 'cat')))", new PSubNullSafeCallInvoke(l, node).toString()); l = new Location(getTestName(), 1); s = definition.getType(Map.class.getSimpleName()).struct; node = new PSubMapShortcut(l, s, new EBinary(l, Operation.ADD, new EConstant(l, 1), new EConstant(l, 4))); node.prefix = new EVariable(l, "a"); assertEquals("(PSubMapShortcut (EVariable a) (EBinary (EConstant Integer 1) + (EConstant Integer 4)))", node.toString()); } public void testPSubShortcut() { Location l = new Location(getTestName(), 0); Struct s = definition.getType(FeatureTest.class.getName()).struct; Method getter = s.methods.get(new MethodKey("getX", 0)); Method setter = s.methods.get(new MethodKey("setX", 1)); PSubShortcut node = new PSubShortcut(l, "x", FeatureTest.class.getName(), getter, setter); node.prefix = new EVariable(l, "a"); assertEquals("(PSubShortcut (EVariable a) x)", node.toString()); assertEquals("(PSubNullSafeCallInvoke (PSubShortcut (EVariable a) x))", new PSubNullSafeCallInvoke(l, node).toString()); } public void testSBreak() { assertToString( "(SSource\n" + " (SDeclBlock (SDeclaration int itr (ENumeric 2)))\n" + " (SDeclBlock (SDeclaration int a (ENumeric 1)))\n" + " (SDeclBlock (SDeclaration int b (ENumeric 1)))\n" + " (SDo (EComp (EVariable b) < (ENumeric 1000)) (SBlock\n" + " (SExpression (EAssignment (EVariable itr) ++ post))\n" + " (SIf (EComp (EVariable itr) > (ENumeric 10000)) (SBlock (SBreak)))\n" + " (SDeclBlock (SDeclaration int tmp (EVariable a)))\n" + " (SExpression (EAssignment (EVariable a) = (EVariable b)))\n" + " (SExpression (EAssignment (EVariable b) = (EBinary (EVariable tmp) + (EVariable b))))))\n" + " (SReturn (EVariable b)))", "int itr = 2;\n" + "int a = 1;\n" + "int b = 1;\n" + "do {\n" + " itr++;\n" + " if (itr > 10000) {\n" + " break\n" + " }\n" + " int tmp = a;\n" + " a = b;\n" + " b = tmp + b\n" + "} while (b < 1000);\n" + "return b"); } public void testSContinue() { assertToString( "(SSource\n" + " (SDeclBlock (SDeclaration int itr (ENumeric 2)))\n" + " (SDeclBlock (SDeclaration int a (ENumeric 1)))\n" + " (SDeclBlock (SDeclaration int b (ENumeric 1)))\n" + " (SDo (EComp (EVariable b) < (ENumeric 1000)) (SBlock\n" + " (SExpression (EAssignment (EVariable itr) ++ post))\n" + " (SIf (EComp (EVariable itr) < (ENumeric 10000)) (SBlock (SContinue)))\n" + " (SDeclBlock (SDeclaration int tmp (EVariable a)))\n" + " (SExpression (EAssignment (EVariable a) = (EVariable b)))\n" + " (SExpression (EAssignment (EVariable b) = (EBinary (EVariable tmp) + (EVariable b))))))\n" + " (SReturn (EVariable b)))", "int itr = 2;\n" + "int a = 1;\n" + "int b = 1;\n" + "do {\n" + " itr++;\n" + " if (itr < 10000) {\n" + " continue\n" + " }\n" + " int tmp = a;\n" + " a = b;\n" + " b = tmp + b\n" + "} while (b < 1000);\n" + "return b"); } public void testSDeclBlock() { assertToString( "(SSource\n" + " (SDeclBlock (SDeclaration def a))\n" + " (SExpression (EAssignment (EVariable a) = (ENumeric 10)))\n" + " (SReturn (EVariable a)))", "def a;\n" + "a = 10;\n" + "return a"); assertToString( "(SSource\n" + " (SDeclBlock (SDeclaration def a (ENumeric 10)))\n" + " (SReturn (EVariable a)))", "def a = 10;\n" + "return a"); assertToString( "(SSource\n" + " (SDeclBlock\n" + " (SDeclaration def a)\n" + " (SDeclaration def b)\n" + " (SDeclaration def c))\n" + " (SReturn (EVariable a)))", "def a, b, c;\n" + "return a"); assertToString( "(SSource\n" + " (SDeclBlock\n" + " (SDeclaration def a (ENumeric 10))\n" + " (SDeclaration def b (ENumeric 20))\n" + " (SDeclaration def c (ENumeric 100)))\n" + " (SReturn (EVariable a)))", "def a = 10, b = 20, c = 100;\n" + "return a"); assertToString( "(SSource\n" + " (SDeclBlock\n" + " (SDeclaration def a (ENumeric 10))\n" + " (SDeclaration def b)\n" + " (SDeclaration def c (ENumeric 100)))\n" + " (SReturn (EVariable a)))", "def a = 10, b, c = 100;\n" + "return a"); assertToString( "(SSource\n" + " (SIf (PField (EVariable params) a) (SBlock\n" + " (SDeclBlock\n" + " (SDeclaration def a (ENumeric 10))\n" + " (SDeclaration def b)\n" + " (SDeclaration def c (ENumeric 100)))\n" + " (SReturn (EVariable a))))\n" + " (SReturn (EBoolean false)))", "if (params.a) {" + " def a = 10, b, c = 100;\n" + " return a\n" + "}\n" + "return false"); } public void testSDo() { assertToString( "(SSource\n" + " (SDeclBlock (SDeclaration int itr (ENumeric 2)))\n" + " (SDeclBlock (SDeclaration int a (ENumeric 1)))\n" + " (SDeclBlock (SDeclaration int b (ENumeric 1)))\n" + " (SDo (EComp (EVariable b) < (ENumeric 1000)) (SBlock\n" + " (SExpression (EAssignment (EVariable itr) ++ post))\n" + " (SDeclBlock (SDeclaration int tmp (EVariable a)))\n" + " (SExpression (EAssignment (EVariable a) = (EVariable b)))\n" + " (SExpression (EAssignment (EVariable b) = (EBinary (EVariable tmp) + (EVariable b))))))\n" + " (SReturn (EVariable b)))", "int itr = 2;\n" + "int a = 1;\n" + "int b = 1;\n" + "do {\n" + " itr++;\n" + " int tmp = a;\n" + " a = b;\n" + " b = tmp + b\n" + "} while (b < 1000);\n" + "return b"); } public void testSEach() { assertToString( "(SSource\n" + " (SDeclBlock (SDeclaration int l (ENumeric 0)))\n" + " (SEach String s (EListInit (EString 'cat') (EString 'dog') (EString 'chicken')) (SBlock " + "(SExpression (EAssignment (EVariable l) += (PCallInvoke (EVariable s) length)))))\n" + " (SReturn (EVariable l)))", "int l = 0;\n" + "for (String s : ['cat', 'dog', 'chicken']) {\n" + " l += s.length()\n" + "}\n" + "return l"); assertToString( "(SSource\n" + " (SDeclBlock (SDeclaration int l (ENumeric 0)))\n" + " (SEach String s (EListInit (EString 'cat') (EString 'dog') (EString 'chicken')) (SBlock\n" + " (SDeclBlock (SDeclaration String s2 (EBinary (EString 'dire ') + (EVariable s))))\n" + " (SExpression (EAssignment (EVariable l) += (PCallInvoke (EVariable s2) length)))))\n" + " (SReturn (EVariable l)))", "int l = 0;\n" + "for (String s : ['cat', 'dog', 'chicken']) {\n" + " String s2 = 'dire ' + s;\n" + " l += s2.length()\n" + "}\n" + "return l"); } public void testSFor() { assertToString( "(SSource\n" + " (SDeclBlock (SDeclaration int sum (ENumeric 0)))\n" + " (SFor\n" + " (SDeclBlock (SDeclaration int i (ENumeric 0)))\n" + " (EComp (EVariable i) < (ENumeric 1000))\n" + " (EAssignment (EVariable i) ++ post)\n" + " (SBlock (SExpression (EAssignment (EVariable sum) += (EVariable i)))))\n" + " (SReturn (EVariable sum)))", "int sum = 0;\n" + "for (int i = 0; i < 1000; i++) {\n" + " sum += i\n" + "}\n" + "return sum"); assertToString( "(SSource\n" + " (SDeclBlock (SDeclaration int sum (ENumeric 0)))\n" + " (SFor\n" + " (SDeclBlock (SDeclaration int i (ENumeric 0)))\n" + " (EComp (EVariable i) < (ENumeric 1000))\n" + " (EAssignment (EVariable i) ++ post)\n" + " (SBlock (SFor\n" + " (SDeclBlock (SDeclaration int j (ENumeric 0)))\n" + " (EComp (EVariable j) < (ENumeric 1000))\n" + " (EAssignment (EVariable j) ++ post)\n" + " (SBlock (SExpression (EAssignment (EVariable sum) += (EBinary (EVariable i) * (EVariable j))))))))\n" + " (SReturn (EVariable sum)))", "int sum = 0;\n" + "for (int i = 0; i < 1000; i++) {\n" + " for (int j = 0; j < 1000; j++) {\n" + " sum += i * j\n" + " }\n" + "}\n" + "return sum"); } public void testSIf() { assertToString( "(SSource (SIf (PField (EVariable param) a) (SBlock (SReturn (EBoolean true)))))", "if (param.a) {\n" + " return true\n" +"}"); assertToString( "(SSource (SIf (PField (EVariable param) a) (SBlock\n" + " (SIf (PField (EVariable param) b) (SBlock (SReturn (EBoolean true))))\n" + " (SReturn (EBoolean false)))))", "if (param.a) {\n" + " if (param.b) {\n" + " return true\n" + " }\n" + " return false\n" +"}"); } public void testSIfElse() { assertToString( "(SSource (SIfElse (PField (EVariable param) a)\n" + " (SBlock (SReturn (EBoolean true)))\n" + " (SBlock (SReturn (EBoolean false)))))", "if (param.a) {\n" + " return true\n" + "} else {\n" + " return false\n" + "}"); assertToString( "(SSource\n" + " (SDeclBlock (SDeclaration int i (ENumeric 0)))\n" + " (SIfElse (PField (EVariable param) a)\n" + " (SBlock (SIfElse (PField (EVariable param) b)\n" + " (SBlock (SReturn (EBoolean true)))\n" + " (SBlock (SReturn (EString 'cat')))))\n" + " (SBlock (SReturn (EBoolean false)))))", "int i = 0;\n" + "if (param.a) {\n" + " if (param.b) {\n" + " return true\n" + " } else {\n" + " return 'cat'\n" + " }\n" + "} else {" + " return false\n" + "}"); } public void testSSubEachArray() { Location l = new Location(getTestName(), 0); Variable v = new Variable(l, "test", Definition.INT_TYPE, 5, false); AExpression e = new ENewArray(l, "int", Arrays.asList(new EConstant(l, 1), new EConstant(l, 2), new EConstant(l, 3)), true); SBlock b = new SBlock(l, singletonList(new SReturn(l, new EConstant(l, 5)))); SSubEachArray node = new SSubEachArray(l, v, e, b); assertEquals( "(SSubEachArray int test (ENewArray int init (Args (EConstant Integer 1) (EConstant Integer 2) (EConstant Integer 3))) " + "(SBlock (SReturn (EConstant Integer 5))))", node.toString()); } public void testSSubEachIterable() { Location l = new Location(getTestName(), 0); Variable v = new Variable(l, "test", Definition.INT_TYPE, 5, false); AExpression e = new EListInit(l, Arrays.asList(new EConstant(l, 1), new EConstant(l, 2), new EConstant(l, 3))); SBlock b = new SBlock(l, singletonList(new SReturn(l, new EConstant(l, 5)))); SSubEachIterable node = new SSubEachIterable(l, v, e, b); assertEquals( "(SSubEachIterable int test (EListInit (EConstant Integer 1) (EConstant Integer 2) (EConstant Integer 3)) (SBlock " + "(SReturn (EConstant Integer 5))))", node.toString()); } public void testSThrow() { assertToString("(SSource (SThrow (ENewObj RuntimeException)))", "throw new RuntimeException()"); } public void testSWhile() { assertToString( "(SSource\n" + " (SDeclBlock (SDeclaration int i (ENumeric 0)))\n" + " (SWhile (EComp (EVariable i) < (ENumeric 10)) (SBlock (SExpression (EAssignment (EVariable i) ++ post))))\n" + " (SReturn (EVariable i)))", "int i = 0;\n" + "while (i < 10) {\n" + " i++\n" + "}\n" + "return i"); } public void testSFunction() { assertToString( "(SSource\n" + " (SFunction def a\n" + " (SReturn (EBoolean true)))\n" + " (SReturn (EBoolean true)))", "def a() {\n" + " return true\n" + "}\n" + "return true"); assertToString( "(SSource\n" + " (SFunction def a (Args (Pair int i) (Pair int j))\n" + " (SReturn (EBoolean true)))\n" + " (SReturn (EBoolean true)))", "def a(int i, int j) {\n" + " return true\n" + "}\n" + "return true"); assertToString( "(SSource\n" + " (SFunction def a (Args (Pair int i) (Pair int j))\n" + " (SIf (EComp (EVariable i) < (EVariable j)) (SBlock (SReturn (EBoolean true))))\n" + " (SDeclBlock (SDeclaration int k (EBinary (EVariable i) + (EVariable j))))\n" + " (SReturn (EVariable k)))\n" + " (SReturn (EBoolean true)))", "def a(int i, int j) {\n" + " if (i < j) {\n" + " return true\n" + " }\n" + " int k = i + j;\n" + " return k\n" + "}\n" + "return true"); assertToString( "(SSource\n" + " (SFunction def a\n" + " (SReturn (EBoolean true)))\n" + " (SFunction def b\n" + " (SReturn (EBoolean false)))\n" + " (SReturn (EBoolean true)))", "def a() {\n" + " return true\n" + "}\n" + "def b() {\n" + " return false\n" + "}\n" + "return true"); } public void testSTryAndSCatch() { assertToString( "(SSource (STry (SBlock (SReturn (ENumeric 1)))\n" + " (SCatch Exception e (SBlock (SReturn (ENumeric 2))))))", "try {\n" + " return 1\n" + "} catch (Exception e) {\n" + " return 2\n" + "}"); assertToString( "(SSource (STry (SBlock\n" + " (SDeclBlock (SDeclaration int i (ENumeric 1)))\n" + " (SReturn (ENumeric 1)))\n" + " (SCatch Exception e (SBlock (SReturn (ENumeric 2))))))", "try {\n" + " int i = 1;" + " return 1\n" + "} catch (Exception e) {\n" + " return 2\n" + "}"); assertToString( "(SSource (STry (SBlock (SReturn (ENumeric 1)))\n" + " (SCatch Exception e (SBlock\n" + " (SDeclBlock (SDeclaration int i (ENumeric 1)))\n" + " (SReturn (ENumeric 2))))))", "try {\n" + " return 1\n" + "} catch (Exception e) {" + " int i = 1;\n" + " return 2\n" + "}"); assertToString( "(SSource (STry (SBlock (SReturn (ENumeric 1)))\n" + " (SCatch NullPointerException e (SBlock (SReturn (ENumeric 2))))\n" + " (SCatch Exception e (SBlock (SReturn (ENumeric 3))))))", "try {\n" + " return 1\n" + "} catch (NullPointerException e) {\n" + " return 2\n" + "} catch (Exception e) {\n" + " return 3\n" + "}"); } private void assertToString(String expected, String code) { assertEquals(expected, walk(code).toString()); } private SSource walk(String code) { ScriptInterface scriptInterface = new ScriptInterface(definition, GenericElasticsearchScript.class); CompilerSettings compilerSettings = new CompilerSettings(); compilerSettings.setRegexesEnabled(true); try { return Walker.buildPainlessTree(scriptInterface, getTestName(), code, compilerSettings, definition, null); } catch (Exception e) { throw new AssertionError("Failed to compile: " + code, e); } } }