Add nodes to handle types (#49785)

This PR adds 3 nodes to handle types defined by a front-end creating a 
Painless AST. These types are decided with data immutability in mind - 
hence the reason for more than a single node.
This commit is contained in:
Jack Conradson 2019-12-05 16:57:45 -08:00
parent abd6fa149c
commit cd3744c0b7
6 changed files with 247 additions and 60 deletions

View File

@ -109,6 +109,7 @@ import org.elasticsearch.painless.lookup.PainlessLookup;
import org.elasticsearch.painless.node.AExpression;
import org.elasticsearch.painless.node.ANode;
import org.elasticsearch.painless.node.AStatement;
import org.elasticsearch.painless.node.DUnresolvedType;
import org.elasticsearch.painless.node.EAssignment;
import org.elasticsearch.painless.node.EBinary;
import org.elasticsearch.painless.node.EBool;
@ -478,8 +479,9 @@ public final class Walker extends PainlessParserBaseVisitor<ANode> {
for (DeclvarContext declvar : ctx.declvar()) {
String name = declvar.ID().getText();
AExpression expression = declvar.expression() == null ? null : (AExpression)visit(declvar.expression());
DUnresolvedType unresolvedType = new DUnresolvedType(location(declvar), type);
declarations.add(new SDeclaration(location(declvar), type, name, expression));
declarations.add(new SDeclaration(location(declvar), unresolvedType, name, expression));
}
return new SDeclBlock(location(ctx), declarations);

View File

@ -0,0 +1,81 @@
/*
* 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.Location;
import org.elasticsearch.painless.lookup.PainlessLookup;
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
import java.util.Objects;
/**
* Represents a Painless type as a {@link Class}. This may still
* require resolution to ensure the type in the {@link PainlessLookup}.
*/
public class DResolvedType extends DType {
protected final Class<?> type;
/**
* If set to {@code true} ensures the type is in the {@link PainlessLookup}.
* If set to {@code false} assumes the type is valid.
*/
protected final boolean checkInLookup;
public DResolvedType(Location location, Class<?> type) {
this(location, type, true);
}
public DResolvedType(Location location, Class<?> type, boolean checkInLookup) {
super(location);
this.type = Objects.requireNonNull(type);
this.checkInLookup = checkInLookup;
}
/**
* If {@link #checkInLookup} is {@code true} checks if the type is in the
* {@link PainlessLookup}, otherwise returns {@code this}.
* @throws IllegalArgumentException if both checking the type is in the {@link PainlessLookup}
* and the type cannot be resolved from the {@link PainlessLookup}
* @return a {@link DResolvedType} where the resolved Painless type is retrievable
*/
@Override
public DResolvedType resolveType(PainlessLookup painlessLookup) {
if (checkInLookup == false) {
return this;
}
if (painlessLookup.getClasses().contains(type) == false) {
throw location.createError(new IllegalArgumentException(
"cannot resolve type [" + PainlessLookupUtility.typeToCanonicalTypeName(type) + "]"));
}
return new DResolvedType(location, type, false);
}
public Class<?> getType() {
return type;
}
@Override
public String toString() {
return " (DResolvedType [" + PainlessLookupUtility.typeToCanonicalTypeName(type) + "])";
}
}

View File

@ -0,0 +1,46 @@
/*
* 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.Location;
import org.elasticsearch.painless.lookup.PainlessLookup;
import java.util.Objects;
/**
* Represents an abstract Painless type. {@link DType} nodes must be
* resolved using {@link #resolveType(PainlessLookup)} to retrieve the
* actual Painless type. {@link DType} exists as a base class so consumers
* may have either a {@link DUnresolvedType} representing a Painless
* canonical type name or a {@link DResolvedType} representing a Painless
* type as the Painless AST is constructed. This allows Painless types already
* resolved at the time of Painless AST construction to not be forced to
* convert back to a Painless canonical type name and then re-resolved.
*/
public abstract class DType {
protected final Location location;
public DType(Location location) {
this.location = Objects.requireNonNull(location);
}
public abstract DResolvedType resolveType(PainlessLookup painlessLookup);
}

View File

@ -0,0 +1,61 @@
/*
* 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.Location;
import org.elasticsearch.painless.lookup.PainlessLookup;
import java.util.Objects;
/**
* Represents a canonical Painless type name as a {@link String}
* that requires resolution.
*/
public class DUnresolvedType extends DType {
protected final String typeName;
public DUnresolvedType(Location location, String typeName) {
super(location);
this.typeName = Objects.requireNonNull(typeName);
}
/**
* Resolves the canonical Painless type name to a Painless type.
* @throws IllegalArgumentException if the type cannot be resolved from the {@link PainlessLookup}
* @return a {@link DResolvedType} where the resolved Painless type is retrievable
*/
@Override
public DResolvedType resolveType(PainlessLookup painlessLookup) {
Class<?> type = painlessLookup.canonicalTypeNameToType(typeName);
if (type == null) {
throw location.createError(new IllegalArgumentException("cannot resolve type [" + typeName + "]"));
}
return new DResolvedType(location, type);
}
@Override
public String toString() {
return "(DUnresolvedType [" + typeName + "])";
}
}

View File

@ -36,13 +36,13 @@ import java.util.Set;
*/
public final class SDeclaration extends AStatement {
private final String type;
private final DType type;
private final String name;
private AExpression expression;
private Variable variable = null;
public SDeclaration(Location location, String type, String name, AExpression expression) {
public SDeclaration(Location location, DType type, String name, AExpression expression) {
super(location);
this.type = Objects.requireNonNull(type);
@ -61,19 +61,15 @@ public final class SDeclaration extends AStatement {
@Override
void analyze(ScriptRoot scriptRoot, Locals locals) {
Class<?> clazz = scriptRoot.getPainlessLookup().canonicalTypeNameToType(this.type);
if (clazz == null) {
throw createError(new IllegalArgumentException("Not a type [" + this.type + "]."));
}
DResolvedType resolvedType = type.resolveType(scriptRoot.getPainlessLookup());
if (expression != null) {
expression.expected = clazz;
expression.expected = resolvedType.getType();
expression.analyze(scriptRoot, locals);
expression = expression.cast(scriptRoot, locals);
}
variable = locals.addVariable(location, clazz, name, false);
variable = locals.addVariable(location, resolvedType.getType(), name, false);
}
@Override

View File

@ -54,7 +54,7 @@ public class NodeToStringTests extends ESTestCase {
public void testEAssignment() {
assertToString(
"(SClass\n"
+ " (SDeclBlock (SDeclaration def i))\n"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [def]) i))\n"
+ " (SExpression (EAssignment (EVariable i) = (ENumeric 2)))\n"
+ " (SReturn (EVariable i)))",
"def i;\n"
@ -63,7 +63,7 @@ public class NodeToStringTests extends ESTestCase {
for (String operator : new String[] {"+", "-", "*", "/", "%", "&", "^", "|", "<<", ">>", ">>>"}) {
assertToString(
"(SClass\n"
+ " (SDeclBlock (SDeclaration def i (ENumeric 1)))\n"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [def]) i (ENumeric 1)))\n"
+ " (SExpression (EAssignment (EVariable i) " + operator + "= (ENumeric 2)))\n"
+ " (SReturn (EVariable i)))",
"def i = 1;\n"
@ -73,31 +73,31 @@ public class NodeToStringTests extends ESTestCase {
// Compound
assertToString(
"(SClass\n"
+ " (SDeclBlock (SDeclaration def i))\n"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [def]) i))\n"
+ " (SReturn (EAssignment (EVariable i) = (ENumeric 2))))",
"def i;\n"
+ "return i = 2");
assertToString(
"(SClass\n"
+ " (SDeclBlock (SDeclaration def i))\n"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [def]) i))\n"
+ " (SReturn (EAssignment (EVariable i) ++ post)))",
"def i;\n"
+ "return i++");
assertToString(
"(SClass\n"
+ " (SDeclBlock (SDeclaration def i))\n"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [def]) i))\n"
+ " (SReturn (EAssignment (EVariable i) ++ pre)))",
"def i;\n"
+ "return ++i");
assertToString(
"(SClass\n"
+ " (SDeclBlock (SDeclaration def i))\n"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [def]) i))\n"
+ " (SReturn (EAssignment (EVariable i) -- post)))",
"def i;\n"
+ "return i--");
assertToString(
"(SClass\n"
+ " (SDeclBlock (SDeclaration def i))\n"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [def]) i))\n"
+ " (SReturn (EAssignment (EVariable i) -- pre)))",
"def i;\n"
+ "return --i");
@ -153,7 +153,8 @@ public class NodeToStringTests extends ESTestCase {
public void testECapturingFunctionRef() {
assertToString(
"(SClass\n"
+ " (SDeclBlock (SDeclaration Integer x (PCallInvoke (EStatic Integer) valueOf (Args (ENumeric 5)))))\n"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [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)");
@ -349,7 +350,7 @@ public class NodeToStringTests extends ESTestCase {
assertToString("(SClass (SReturn (EVariable params)))", "return params");
assertToString(
"(SClass\n"
+ " (SDeclBlock (SDeclaration def a (ENumeric 1)))\n"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [def]) a (ENumeric 1)))\n"
+ " (SReturn (EVariable a)))",
"def a = 1;\n"
+ "return a");
@ -373,13 +374,13 @@ public class NodeToStringTests extends ESTestCase {
assertToString("(SClass (SReturn (PField nullSafe (EVariable params) a)))", "return params?.a");
assertToString(
"(SClass\n"
+ " (SDeclBlock (SDeclaration int[] a (ENewArray int[] dims (Args (ENumeric 10)))))\n"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [int[]]) a (ENewArray int[] dims (Args (ENumeric 10)))))\n"
+ " (SReturn (PField (EVariable a) length)))",
"int[] a = new int[10];\n"
+ "return a.length");
assertToString(
"(SClass\n"
+ " (SDeclBlock (SDeclaration org.elasticsearch.painless.FeatureTestObject a"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [org.elasticsearch.painless.FeatureTestObject]) a"
+ " (ENewObj org.elasticsearch.painless.FeatureTestObject)))\n"
+ " (SExpression (EAssignment (PField (EVariable a) x) = (ENumeric 10)))\n"
+ " (SReturn (PField (EVariable a) x)))",
@ -511,13 +512,13 @@ public class NodeToStringTests extends ESTestCase {
public void testSBreak() {
assertToString(
"(SClass\n"
+ " (SDeclBlock (SDeclaration int itr (ENumeric 2)))\n"
+ " (SDeclBlock (SDeclaration int a (ENumeric 1)))\n"
+ " (SDeclBlock (SDeclaration int b (ENumeric 1)))\n"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [int]) itr (ENumeric 2)))\n"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [int]) a (ENumeric 1)))\n"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [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"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [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)))",
@ -539,13 +540,13 @@ public class NodeToStringTests extends ESTestCase {
public void testSContinue() {
assertToString(
"(SClass\n"
+ " (SDeclBlock (SDeclaration int itr (ENumeric 2)))\n"
+ " (SDeclBlock (SDeclaration int a (ENumeric 1)))\n"
+ " (SDeclBlock (SDeclaration int b (ENumeric 1)))\n"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [int]) itr (ENumeric 2)))\n"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [int]) a (ENumeric 1)))\n"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [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"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [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)))",
@ -567,7 +568,7 @@ public class NodeToStringTests extends ESTestCase {
public void testSDeclBlock() {
assertToString(
"(SClass\n"
+ " (SDeclBlock (SDeclaration def a))\n"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [def]) a))\n"
+ " (SExpression (EAssignment (EVariable a) = (ENumeric 10)))\n"
+ " (SReturn (EVariable a)))",
"def a;\n"
@ -575,34 +576,34 @@ public class NodeToStringTests extends ESTestCase {
+ "return a");
assertToString(
"(SClass\n"
+ " (SDeclBlock (SDeclaration def a (ENumeric 10)))\n"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [def]) a (ENumeric 10)))\n"
+ " (SReturn (EVariable a)))",
"def a = 10;\n"
+ "return a");
assertToString(
"(SClass\n"
+ " (SDeclBlock\n"
+ " (SDeclaration def a)\n"
+ " (SDeclaration def b)\n"
+ " (SDeclaration def c))\n"
+ " (SDeclaration (DUnresolvedType [def]) a)\n"
+ " (SDeclaration (DUnresolvedType [def]) b)\n"
+ " (SDeclaration (DUnresolvedType [def]) c))\n"
+ " (SReturn (EVariable a)))",
"def a, b, c;\n"
+ "return a");
assertToString(
"(SClass\n"
+ " (SDeclBlock\n"
+ " (SDeclaration def a (ENumeric 10))\n"
+ " (SDeclaration def b (ENumeric 20))\n"
+ " (SDeclaration def c (ENumeric 100)))\n"
+ " (SDeclaration (DUnresolvedType [def]) a (ENumeric 10))\n"
+ " (SDeclaration (DUnresolvedType [def]) b (ENumeric 20))\n"
+ " (SDeclaration (DUnresolvedType [def]) c (ENumeric 100)))\n"
+ " (SReturn (EVariable a)))",
"def a = 10, b = 20, c = 100;\n"
+ "return a");
assertToString(
"(SClass\n"
+ " (SDeclBlock\n"
+ " (SDeclaration def a (ENumeric 10))\n"
+ " (SDeclaration def b)\n"
+ " (SDeclaration def c (ENumeric 100)))\n"
+ " (SDeclaration (DUnresolvedType [def]) a (ENumeric 10))\n"
+ " (SDeclaration (DUnresolvedType [def]) b)\n"
+ " (SDeclaration (DUnresolvedType [def]) c (ENumeric 100)))\n"
+ " (SReturn (EVariable a)))",
"def a = 10, b, c = 100;\n"
+ "return a");
@ -610,9 +611,9 @@ public class NodeToStringTests extends ESTestCase {
"(SClass\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"
+ " (SDeclaration (DUnresolvedType [def]) a (ENumeric 10))\n"
+ " (SDeclaration (DUnresolvedType [def]) b)\n"
+ " (SDeclaration (DUnresolvedType [def]) c (ENumeric 100)))\n"
+ " (SReturn (EVariable a))))\n"
+ " (SReturn (EBoolean false)))",
"if (params.a) {"
@ -625,12 +626,12 @@ public class NodeToStringTests extends ESTestCase {
public void testSDo() {
assertToString(
"(SClass\n"
+ " (SDeclBlock (SDeclaration int itr (ENumeric 2)))\n"
+ " (SDeclBlock (SDeclaration int a (ENumeric 1)))\n"
+ " (SDeclBlock (SDeclaration int b (ENumeric 1)))\n"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [int]) itr (ENumeric 2)))\n"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [int]) a (ENumeric 1)))\n"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [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"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [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)))",
@ -649,7 +650,7 @@ public class NodeToStringTests extends ESTestCase {
public void testSEach() {
assertToString(
"(SClass\n"
+ " (SDeclBlock (SDeclaration int l (ENumeric 0)))\n"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [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)))",
@ -660,9 +661,9 @@ public class NodeToStringTests extends ESTestCase {
+ "return l");
assertToString(
"(SClass\n"
+ " (SDeclBlock (SDeclaration int l (ENumeric 0)))\n"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [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"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [String]) s2 (EBinary (EString 'dire ') + (EVariable s))))\n"
+ " (SExpression (EAssignment (EVariable l) += (PCallInvoke (EVariable s2) length)))))\n"
+ " (SReturn (EVariable l)))",
"int l = 0;\n"
@ -676,9 +677,9 @@ public class NodeToStringTests extends ESTestCase {
public void testSFor() {
assertToString(
"(SClass\n"
+ " (SDeclBlock (SDeclaration int sum (ENumeric 0)))\n"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [int]) sum (ENumeric 0)))\n"
+ " (SFor\n"
+ " (SDeclBlock (SDeclaration int i (ENumeric 0)))\n"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [int]) i (ENumeric 0)))\n"
+ " (EComp (EVariable i) < (ENumeric 1000))\n"
+ " (EAssignment (EVariable i) ++ post)\n"
+ " (SBlock (SExpression (EAssignment (EVariable sum) += (EVariable i)))))\n"
@ -690,13 +691,13 @@ public class NodeToStringTests extends ESTestCase {
+ "return sum");
assertToString(
"(SClass\n"
+ " (SDeclBlock (SDeclaration int sum (ENumeric 0)))\n"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [int]) sum (ENumeric 0)))\n"
+ " (SFor\n"
+ " (SDeclBlock (SDeclaration int i (ENumeric 0)))\n"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [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"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [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"
@ -740,7 +741,7 @@ public class NodeToStringTests extends ESTestCase {
+ "}");
assertToString(
"(SClass\n"
+ " (SDeclBlock (SDeclaration int i (ENumeric 0)))\n"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [int]) i (ENumeric 0)))\n"
+ " (SIfElse (PField (EVariable param) a)\n"
+ " (SBlock (SIfElse (PField (EVariable param) b)\n"
+ " (SBlock (SReturn (EBoolean true)))\n"
@ -789,7 +790,7 @@ public class NodeToStringTests extends ESTestCase {
public void testSWhile() {
assertToString(
"(SClass\n"
+ " (SDeclBlock (SDeclaration int i (ENumeric 0)))\n"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [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"
@ -822,7 +823,7 @@ public class NodeToStringTests extends ESTestCase {
"(SClass\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"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [int]) k (EBinary (EVariable i) + (EVariable j))))\n"
+ " (SReturn (EVariable k)))\n"
+ " (SReturn (EBoolean true)))",
"def a(int i, int j) {\n"
@ -860,7 +861,7 @@ public class NodeToStringTests extends ESTestCase {
+ "}");
assertToString(
"(SClass (STry (SBlock\n"
+ " (SDeclBlock (SDeclaration int i (ENumeric 1)))\n"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [int]) i (ENumeric 1)))\n"
+ " (SReturn (ENumeric 1)))\n"
+ " (SCatch Exception e (SBlock (SReturn (ENumeric 2))))))",
"try {\n"
@ -872,7 +873,7 @@ public class NodeToStringTests extends ESTestCase {
assertToString(
"(SClass (STry (SBlock (SReturn (ENumeric 1)))\n"
+ " (SCatch Exception e (SBlock\n"
+ " (SDeclBlock (SDeclaration int i (ENumeric 1)))\n"
+ " (SDeclBlock (SDeclaration (DUnresolvedType [int]) i (ENumeric 1)))\n"
+ " (SReturn (ENumeric 2))))))",
"try {\n"
+ " return 1\n"