Skip to content
This repository was archived by the owner on Dec 8, 2025. It is now read-only.

Commit 38ce80e

Browse files
authored
Support .length() calls (#1151)
Fixes #1148.
1 parent f796df5 commit 38ce80e

12 files changed

Lines changed: 268 additions & 41 deletions

File tree

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright 2021 The GraphicsFuzz Project Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.graphicsfuzz.common.ast.expr;
18+
19+
import com.graphicsfuzz.common.ast.IAstNode;
20+
import com.graphicsfuzz.common.ast.visitors.IAstVisitor;
21+
import java.util.Collections;
22+
23+
public class LengthExpr extends Expr {
24+
25+
private Expr receiver;
26+
27+
public LengthExpr(Expr receiver) {
28+
setReceiver(receiver);
29+
}
30+
31+
public Expr getReceiver() {
32+
return receiver;
33+
}
34+
35+
public void setReceiver(Expr receiver) {
36+
checkNoTopLevelCommaExpression(Collections.singletonList(receiver));
37+
if (receiver == null) {
38+
throw new IllegalArgumentException("Length expression cannot have null receiver");
39+
}
40+
this.receiver = receiver;
41+
}
42+
43+
@Override
44+
public void accept(IAstVisitor visitor) {
45+
visitor.visitLengthExpr(this);
46+
}
47+
48+
@Override
49+
public LengthExpr clone() {
50+
return new LengthExpr(receiver.clone());
51+
}
52+
53+
@Override
54+
public Expr getChild(int index) {
55+
if (index == 0) {
56+
return receiver;
57+
}
58+
throw new IndexOutOfBoundsException("Index for LengthExpr must be 0");
59+
}
60+
61+
@Override
62+
public void setChild(int index, Expr expr) {
63+
if (index == 0) {
64+
setReceiver(expr);
65+
return;
66+
}
67+
throw new IndexOutOfBoundsException("Index for LengthExpr must be 0");
68+
}
69+
70+
@Override
71+
public int getNumChildren() {
72+
return 1;
73+
}
74+
75+
@Override
76+
public boolean hasChild(IAstNode candidateChild) {
77+
return receiver == candidateChild;
78+
}
79+
}

ast/src/main/java/com/graphicsfuzz/common/ast/expr/MemberLookupExpr.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ public class MemberLookupExpr extends Expr {
2626
private String member;
2727

2828
public MemberLookupExpr(Expr structure, String member) {
29-
checkNoTopLevelCommaExpression(Collections.singletonList(structure));
3029
setStructure(structure);
3130
this.member = member;
3231
}
@@ -36,8 +35,9 @@ public Expr getStructure() {
3635
}
3736

3837
public void setStructure(Expr structure) {
38+
checkNoTopLevelCommaExpression(Collections.singletonList(structure));
3939
if (structure == null) {
40-
throw new IllegalArgumentException("Member lookup expression canno have null structure");
40+
throw new IllegalArgumentException("Member lookup expression cannot have null structure");
4141
}
4242
this.structure = structure;
4343
}

ast/src/main/java/com/graphicsfuzz/common/ast/visitors/AstBuilder.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import com.graphicsfuzz.common.ast.expr.FloatConstantExpr;
3838
import com.graphicsfuzz.common.ast.expr.FunctionCallExpr;
3939
import com.graphicsfuzz.common.ast.expr.IntConstantExpr;
40+
import com.graphicsfuzz.common.ast.expr.LengthExpr;
4041
import com.graphicsfuzz.common.ast.expr.MemberLookupExpr;
4142
import com.graphicsfuzz.common.ast.expr.ParenExpr;
4243
import com.graphicsfuzz.common.ast.expr.TernaryExpr;
@@ -1360,8 +1361,18 @@ public Expr visitPostfix_expression(Postfix_expressionContext ctx) {
13601361
visitExpression(ctx.integer_expression().expression()));
13611362
}
13621363
if (ctx.method_call_generic() != null) {
1363-
throw new UnsupportedLanguageFeatureException("Method calls are not currently supported: "
1364-
+ getOriginalSourceText(ctx));
1364+
if (ctx.method_call_generic().method_call_header_with_parameters() != null) {
1365+
throw new UnsupportedLanguageFeatureException("Method calls with parameters are "
1366+
+ "allowed by the GLSL grammar but have no meaning in the language at present: "
1367+
+ getOriginalSourceText(ctx));
1368+
}
1369+
if (!ctx.method_call_generic().method_call_header_no_parameters().method_call_header()
1370+
.variable_identifier().IDENTIFIER().getText().equals("length")) {
1371+
throw new UnsupportedLanguageFeatureException("The only allowed method call in GLSL is to"
1372+
+ " length(); found: "
1373+
+ getOriginalSourceText(ctx));
1374+
}
1375+
return new LengthExpr(visitPostfix_expression(ctx.postfix_expression()));
13651376
}
13661377
if (ctx.IDENTIFIER() != null) {
13671378
return new MemberLookupExpr(visitPostfix_expression(ctx.postfix_expression()),

ast/src/main/java/com/graphicsfuzz/common/ast/visitors/IAstVisitor.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import com.graphicsfuzz.common.ast.expr.FloatConstantExpr;
3636
import com.graphicsfuzz.common.ast.expr.FunctionCallExpr;
3737
import com.graphicsfuzz.common.ast.expr.IntConstantExpr;
38+
import com.graphicsfuzz.common.ast.expr.LengthExpr;
3839
import com.graphicsfuzz.common.ast.expr.MemberLookupExpr;
3940
import com.graphicsfuzz.common.ast.expr.ParenExpr;
4041
import com.graphicsfuzz.common.ast.expr.TernaryExpr;
@@ -175,4 +176,6 @@ public interface IAstVisitor {
175176

176177
void visitPragmaStatement(PragmaStatement pragmaStatement);
177178

179+
void visitLengthExpr(LengthExpr lengthExpr);
180+
178181
}

ast/src/main/java/com/graphicsfuzz/common/ast/visitors/StandardVisitor.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import com.graphicsfuzz.common.ast.expr.FloatConstantExpr;
3838
import com.graphicsfuzz.common.ast.expr.FunctionCallExpr;
3939
import com.graphicsfuzz.common.ast.expr.IntConstantExpr;
40+
import com.graphicsfuzz.common.ast.expr.LengthExpr;
4041
import com.graphicsfuzz.common.ast.expr.MemberLookupExpr;
4142
import com.graphicsfuzz.common.ast.expr.ParenExpr;
4243
import com.graphicsfuzz.common.ast.expr.TernaryExpr;
@@ -405,8 +406,9 @@ public void visitPragmaStatement(PragmaStatement pragmaStatement) {
405406

406407
}
407408

408-
public final void abortVisitation() {
409-
throw new AbortVisitationException();
409+
@Override
410+
public void visitLengthExpr(LengthExpr lengthExpr) {
411+
visitChildFromParent(lengthExpr.getReceiver(), lengthExpr);
410412
}
411413

412414
protected <T extends IAstNode> void visitChildFromParent(Consumer<T> visitorMethod, T child,

ast/src/main/java/com/graphicsfuzz/common/tool/PrettyPrinterVisitor.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import com.graphicsfuzz.common.ast.expr.FloatConstantExpr;
3636
import com.graphicsfuzz.common.ast.expr.FunctionCallExpr;
3737
import com.graphicsfuzz.common.ast.expr.IntConstantExpr;
38+
import com.graphicsfuzz.common.ast.expr.LengthExpr;
3839
import com.graphicsfuzz.common.ast.expr.MemberLookupExpr;
3940
import com.graphicsfuzz.common.ast.expr.ParenExpr;
4041
import com.graphicsfuzz.common.ast.expr.TernaryExpr;
@@ -404,6 +405,12 @@ public void visitMemberLookupExpr(MemberLookupExpr memberLookupExpr) {
404405
out.append(".").append(memberLookupExpr.getMember());
405406
}
406407

408+
@Override
409+
public void visitLengthExpr(LengthExpr lengthExpr) {
410+
visit(lengthExpr.getReceiver());
411+
out.append(".length()");
412+
}
413+
407414
@Override
408415
public void visitIntConstantExpr(IntConstantExpr intConstantExpr) {
409416
out.append(intConstantExpr.getValue());

ast/src/main/java/com/graphicsfuzz/common/typing/Typer.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import com.graphicsfuzz.common.ast.expr.FloatConstantExpr;
3131
import com.graphicsfuzz.common.ast.expr.FunctionCallExpr;
3232
import com.graphicsfuzz.common.ast.expr.IntConstantExpr;
33+
import com.graphicsfuzz.common.ast.expr.LengthExpr;
3334
import com.graphicsfuzz.common.ast.expr.MemberLookupExpr;
3435
import com.graphicsfuzz.common.ast.expr.ParenExpr;
3536
import com.graphicsfuzz.common.ast.expr.TernaryExpr;
@@ -483,6 +484,16 @@ public void visitMemberLookupExpr(MemberLookupExpr memberLookupExpr) {
483484
}
484485
}
485486

487+
@Override
488+
public void visitLengthExpr(LengthExpr lengthExpr) {
489+
super.visitLengthExpr(lengthExpr);
490+
final Type receiverType = types.get(lengthExpr.getReceiver()).getWithoutQualifiers();
491+
assert BasicType.allVectorTypes().contains(receiverType)
492+
|| BasicType.allMatrixTypes().contains(receiverType)
493+
|| receiverType instanceof ArrayType;
494+
types.put(lengthExpr, BasicType.INT);
495+
}
496+
486497
@Override
487498
public void visitArrayConstructorExpr(ArrayConstructorExpr arrayConstructorExpr) {
488499
super.visitArrayConstructorExpr(arrayConstructorExpr);
@@ -546,6 +557,7 @@ public void visitInterfaceBlock(InterfaceBlock interfaceBlock) {
546557
/**
547558
* If the given name corresponds to an OpenGL builtin variable, yields the type of the
548559
* variable.
560+
*
549561
* @param name The name of a candidate builtin variable.
550562
* @return The type of the variable if it is indeed a builtin, otherwise empty.
551563
*/
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* Copyright 2021 The GraphicsFuzz Project Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.graphicsfuzz.common.ast.expr;
18+
19+
import static org.junit.Assert.assertEquals;
20+
import static org.junit.Assert.assertNotSame;
21+
import static org.junit.Assert.assertTrue;
22+
23+
import com.graphicsfuzz.common.ast.visitors.StandardVisitor;
24+
import org.junit.Test;
25+
26+
public class LengthExprTest {
27+
28+
@Test
29+
public void getReceiver() throws Exception {
30+
VariableIdentifierExpr v = new VariableIdentifierExpr("v");
31+
LengthExpr le = new LengthExpr(v);
32+
assertEquals(v, le.getReceiver());
33+
}
34+
35+
@Test
36+
public void setReceiver() throws Exception {
37+
VariableIdentifierExpr v = new VariableIdentifierExpr("v");
38+
VariableIdentifierExpr w = new VariableIdentifierExpr("w");
39+
LengthExpr le = new LengthExpr(v);
40+
le.setReceiver(w);
41+
assertEquals(w, le.getReceiver());
42+
}
43+
44+
@Test
45+
public void accept() throws Exception {
46+
new StandardVisitor() {
47+
@Override
48+
public void visitLengthExpr(LengthExpr memberLookupExpr) {
49+
super.visitLengthExpr(memberLookupExpr);
50+
assertTrue(memberLookupExpr.getReceiver() instanceof VariableIdentifierExpr);
51+
assertEquals("v", ((VariableIdentifierExpr) memberLookupExpr.getReceiver()).getName());
52+
}
53+
}.visit(new LengthExpr(new VariableIdentifierExpr("v")));
54+
}
55+
56+
@Test
57+
public void testClone() throws Exception {
58+
VariableIdentifierExpr v = new VariableIdentifierExpr("v");
59+
LengthExpr le = new LengthExpr(v);
60+
LengthExpr le2 = le.clone();
61+
assertNotSame(le, le2);
62+
assertEquals(((VariableIdentifierExpr) le.getReceiver()).getName(),
63+
((VariableIdentifierExpr) le2.getReceiver()).getName());
64+
assertNotSame(le.getReceiver(), le2.getReceiver());
65+
}
66+
67+
@Test
68+
public void getChild() throws Exception {
69+
VariableIdentifierExpr v = new VariableIdentifierExpr("v");
70+
LengthExpr le = new LengthExpr(v);
71+
assertEquals(v, le.getChild(0));
72+
assertEquals(le.getReceiver(), le.getChild(0));
73+
}
74+
75+
@Test(expected = IndexOutOfBoundsException.class)
76+
public void getChildException() throws Exception {
77+
new LengthExpr(new VariableIdentifierExpr("v")).getChild(1);
78+
}
79+
80+
@Test
81+
public void setChild() throws Exception {
82+
VariableIdentifierExpr v = new VariableIdentifierExpr("v");
83+
VariableIdentifierExpr w = new VariableIdentifierExpr("w");
84+
LengthExpr le = new LengthExpr(v);
85+
le.setChild(0, w);
86+
assertEquals(w, le.getReceiver());
87+
}
88+
89+
@Test(expected = IndexOutOfBoundsException.class)
90+
public void setChildException() throws Exception {
91+
new LengthExpr(new VariableIdentifierExpr("v"))
92+
.setChild(1, new VariableIdentifierExpr("w"));
93+
}
94+
95+
@Test
96+
public void getNumChildren() throws Exception {
97+
VariableIdentifierExpr v = new VariableIdentifierExpr("v");
98+
LengthExpr le = new LengthExpr(v);
99+
assertEquals(1, le.getNumChildren());
100+
}
101+
102+
}

ast/src/test/java/com/graphicsfuzz/common/ast/expr/MemberLookupExprTest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
package com.graphicsfuzz.common.ast.expr;
1818

1919
import static org.junit.Assert.assertEquals;
20-
import static org.junit.Assert.assertFalse;
20+
import static org.junit.Assert.assertNotSame;
2121
import static org.junit.Assert.assertTrue;
2222

2323
import com.graphicsfuzz.common.ast.visitors.StandardVisitor;
@@ -85,11 +85,11 @@ public void testClone() throws Exception {
8585
v,
8686
"foo");
8787
MemberLookupExpr mle2 = mle.clone();
88-
assertFalse(mle == mle2);
88+
assertNotSame(mle, mle2);
8989
assertEquals(mle.getMember(), mle2.getMember());
9090
assertEquals(((VariableIdentifierExpr) mle.getStructure()).getName(),
9191
((VariableIdentifierExpr) mle2.getStructure()).getName());
92-
assertFalse(mle.getStructure() == mle2.getStructure());
92+
assertNotSame(mle.getStructure(), mle2.getStructure());
9393
}
9494

9595
@Test
@@ -133,4 +133,4 @@ public void getNumChildren() throws Exception {
133133
assertEquals(1, mle.getNumChildren());
134134
}
135135

136-
}
136+
}

ast/src/test/java/com/graphicsfuzz/common/tool/PrettyPrinterVisitorTest.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -907,4 +907,16 @@ public void forInShortIf() throws Exception {
907907
assertEquals(shader, PrettyPrinterVisitor.prettyPrintAsString(ParseHelper.parse(shader)));
908908
}
909909

910+
@Test
911+
public void length() throws Exception {
912+
final String shader =
913+
"#version 320 es\n"
914+
+ "void main()\n"
915+
+ "{\n"
916+
+ " int A[5];\n"
917+
+ " int x = A.length();\n"
918+
+ "}\n";
919+
assertEquals(shader, PrettyPrinterVisitor.prettyPrintAsString(ParseHelper.parse(shader)));
920+
}
921+
910922
}

0 commit comments

Comments
 (0)