Skip to content

Commit cd3744c

Browse files
committed
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.
1 parent abd6fa1 commit cd3744c

File tree

6 files changed

+247
-60
lines changed

6 files changed

+247
-60
lines changed

modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/Walker.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@
109109
import org.elasticsearch.painless.node.AExpression;
110110
import org.elasticsearch.painless.node.ANode;
111111
import org.elasticsearch.painless.node.AStatement;
112+
import org.elasticsearch.painless.node.DUnresolvedType;
112113
import org.elasticsearch.painless.node.EAssignment;
113114
import org.elasticsearch.painless.node.EBinary;
114115
import org.elasticsearch.painless.node.EBool;
@@ -478,8 +479,9 @@ public ANode visitDeclaration(DeclarationContext ctx) {
478479
for (DeclvarContext declvar : ctx.declvar()) {
479480
String name = declvar.ID().getText();
480481
AExpression expression = declvar.expression() == null ? null : (AExpression)visit(declvar.expression());
482+
DUnresolvedType unresolvedType = new DUnresolvedType(location(declvar), type);
481483

482-
declarations.add(new SDeclaration(location(declvar), type, name, expression));
484+
declarations.add(new SDeclaration(location(declvar), unresolvedType, name, expression));
483485
}
484486

485487
return new SDeclBlock(location(ctx), declarations);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.painless.node;
21+
22+
import org.elasticsearch.painless.Location;
23+
import org.elasticsearch.painless.lookup.PainlessLookup;
24+
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
25+
26+
import java.util.Objects;
27+
28+
/**
29+
* Represents a Painless type as a {@link Class}. This may still
30+
* require resolution to ensure the type in the {@link PainlessLookup}.
31+
*/
32+
public class DResolvedType extends DType {
33+
34+
protected final Class<?> type;
35+
36+
/**
37+
* If set to {@code true} ensures the type is in the {@link PainlessLookup}.
38+
* If set to {@code false} assumes the type is valid.
39+
*/
40+
protected final boolean checkInLookup;
41+
42+
public DResolvedType(Location location, Class<?> type) {
43+
this(location, type, true);
44+
}
45+
46+
public DResolvedType(Location location, Class<?> type, boolean checkInLookup) {
47+
super(location);
48+
this.type = Objects.requireNonNull(type);
49+
this.checkInLookup = checkInLookup;
50+
}
51+
52+
/**
53+
* If {@link #checkInLookup} is {@code true} checks if the type is in the
54+
* {@link PainlessLookup}, otherwise returns {@code this}.
55+
* @throws IllegalArgumentException if both checking the type is in the {@link PainlessLookup}
56+
* and the type cannot be resolved from the {@link PainlessLookup}
57+
* @return a {@link DResolvedType} where the resolved Painless type is retrievable
58+
*/
59+
@Override
60+
public DResolvedType resolveType(PainlessLookup painlessLookup) {
61+
if (checkInLookup == false) {
62+
return this;
63+
}
64+
65+
if (painlessLookup.getClasses().contains(type) == false) {
66+
throw location.createError(new IllegalArgumentException(
67+
"cannot resolve type [" + PainlessLookupUtility.typeToCanonicalTypeName(type) + "]"));
68+
}
69+
70+
return new DResolvedType(location, type, false);
71+
}
72+
73+
public Class<?> getType() {
74+
return type;
75+
}
76+
77+
@Override
78+
public String toString() {
79+
return " (DResolvedType [" + PainlessLookupUtility.typeToCanonicalTypeName(type) + "])";
80+
}
81+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.painless.node;
21+
22+
import org.elasticsearch.painless.Location;
23+
import org.elasticsearch.painless.lookup.PainlessLookup;
24+
25+
import java.util.Objects;
26+
27+
/**
28+
* Represents an abstract Painless type. {@link DType} nodes must be
29+
* resolved using {@link #resolveType(PainlessLookup)} to retrieve the
30+
* actual Painless type. {@link DType} exists as a base class so consumers
31+
* may have either a {@link DUnresolvedType} representing a Painless
32+
* canonical type name or a {@link DResolvedType} representing a Painless
33+
* type as the Painless AST is constructed. This allows Painless types already
34+
* resolved at the time of Painless AST construction to not be forced to
35+
* convert back to a Painless canonical type name and then re-resolved.
36+
*/
37+
public abstract class DType {
38+
39+
protected final Location location;
40+
41+
public DType(Location location) {
42+
this.location = Objects.requireNonNull(location);
43+
}
44+
45+
public abstract DResolvedType resolveType(PainlessLookup painlessLookup);
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.painless.node;
21+
22+
import org.elasticsearch.painless.Location;
23+
import org.elasticsearch.painless.lookup.PainlessLookup;
24+
25+
import java.util.Objects;
26+
27+
/**
28+
* Represents a canonical Painless type name as a {@link String}
29+
* that requires resolution.
30+
*/
31+
public class DUnresolvedType extends DType {
32+
33+
protected final String typeName;
34+
35+
public DUnresolvedType(Location location, String typeName) {
36+
super(location);
37+
this.typeName = Objects.requireNonNull(typeName);
38+
}
39+
40+
/**
41+
* Resolves the canonical Painless type name to a Painless type.
42+
* @throws IllegalArgumentException if the type cannot be resolved from the {@link PainlessLookup}
43+
* @return a {@link DResolvedType} where the resolved Painless type is retrievable
44+
*/
45+
@Override
46+
public DResolvedType resolveType(PainlessLookup painlessLookup) {
47+
Class<?> type = painlessLookup.canonicalTypeNameToType(typeName);
48+
49+
if (type == null) {
50+
throw location.createError(new IllegalArgumentException("cannot resolve type [" + typeName + "]"));
51+
}
52+
53+
return new DResolvedType(location, type);
54+
}
55+
56+
@Override
57+
public String toString() {
58+
return "(DUnresolvedType [" + typeName + "])";
59+
}
60+
}
61+

modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclaration.java

+5-9
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,13 @@
3636
*/
3737
public final class SDeclaration extends AStatement {
3838

39-
private final String type;
39+
private final DType type;
4040
private final String name;
4141
private AExpression expression;
4242

4343
private Variable variable = null;
4444

45-
public SDeclaration(Location location, String type, String name, AExpression expression) {
45+
public SDeclaration(Location location, DType type, String name, AExpression expression) {
4646
super(location);
4747

4848
this.type = Objects.requireNonNull(type);
@@ -61,19 +61,15 @@ void extractVariables(Set<String> variables) {
6161

6262
@Override
6363
void analyze(ScriptRoot scriptRoot, Locals locals) {
64-
Class<?> clazz = scriptRoot.getPainlessLookup().canonicalTypeNameToType(this.type);
65-
66-
if (clazz == null) {
67-
throw createError(new IllegalArgumentException("Not a type [" + this.type + "]."));
68-
}
64+
DResolvedType resolvedType = type.resolveType(scriptRoot.getPainlessLookup());
6965

7066
if (expression != null) {
71-
expression.expected = clazz;
67+
expression.expected = resolvedType.getType();
7268
expression.analyze(scriptRoot, locals);
7369
expression = expression.cast(scriptRoot, locals);
7470
}
7571

76-
variable = locals.addVariable(location, clazz, name, false);
72+
variable = locals.addVariable(location, resolvedType.getType(), name, false);
7773
}
7874

7975
@Override

0 commit comments

Comments
 (0)