Skip to content

Commit 1676fcc

Browse files
author
dlsmith
committed
DynamicJava: Parser improvements.
- Introduced a ModifierSet class; added hooks for annotations on all declarations (but the annotation() parser production still needs to be implemented). - Improved primary expression parsing, fixing some corner-case bugs and handling explicit method/constructor type arguments. - Eliminated most lookahead productions, which are generally unnecessary, were incorrect (constructor call lookahead needed to traverse an entire anonymous class declaration, which it was not doing correctly), and had become inconsistent with the corresponding non-lookahead productions. git-svn-id: file:///tmp/test-svn/trunk@4827 fe72c1cf-3628-48e9-8b72-1c46755d3cff
1 parent f571254 commit 1676fcc

41 files changed

Lines changed: 2227 additions & 3622 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

dynamicjava/build.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -594,7 +594,7 @@
594594
<exclude name="**" />
595595
<!-- Additional test output files should be listed here -->
596596
</fileset>
597-
<fileset dir="${basedir}">
597+
<fileset dir="${basedir}" defaultexcludes="no">
598598
<patternset refid="generated-sources" />
599599
</fileset>
600600
<fileset dir="${basedir}" defaultexcludes="no">

dynamicjava/src/edu/rice/cs/dynamicjava/interpreter/ClassMemberChecker.java

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package edu.rice.cs.dynamicjava.interpreter;
22

3-
import java.lang.reflect.Modifier;
4-
53
import koala.dynamicjava.tree.*;
64
import koala.dynamicjava.tree.tiger.*;
75
import koala.dynamicjava.tree.visitor.*;
@@ -80,7 +78,7 @@ private abstract class SignatureVisitor extends AbstractVisitor<Void> {
8078

8179
for (FormalParameter param : node.getParameters()) {
8280
Type t = sigChecker.check(param.getType());
83-
setVariable(param, new LocalVariable(param.getName(), t, param.isFinal()));
81+
setVariable(param, new LocalVariable(param.getName(), t, param.getModifiers().isFinal()));
8482
}
8583

8684
for (TypeName tn : node.getExceptions()) { sigChecker.check(tn); }
@@ -101,12 +99,12 @@ private class ClassMemberSignatureVisitor extends SignatureVisitor {
10199

102100
@Override public Void visit(MethodDeclaration node) {
103101
super.visit(node);
104-
int access = node.getAccessFlags();
105-
if (Modifier.isAbstract(access) && node.getBody() != null) {
102+
ModifierSet mods = node.getModifiers();
103+
if (mods.isAbstract() && node.getBody() != null) {
106104
setErrorStrings(node, node.getName());
107105
throw new ExecutionError("abstract.method.body", node);
108106
}
109-
else if (!Modifier.isAbstract(access) && node.getBody() == null) {
107+
else if (!mods.isAbstract() && node.getBody() == null) {
110108
setErrorStrings(node, node.getName());
111109
throw new ExecutionError("missing.method.body", node);
112110
}
@@ -133,7 +131,7 @@ else if (!Modifier.isAbstract(access) && node.getBody() == null) {
133131

134132
for (FormalParameter param : node.getParameters()) {
135133
Type t = sigChecker.check(param.getType());
136-
setVariable(param, new LocalVariable(param.getName(), t, param.isFinal()));
134+
setVariable(param, new LocalVariable(param.getName(), t, param.getModifiers().isFinal()));
137135
}
138136

139137
for (TypeName tn : node.getExceptions()) { sigChecker.check(tn); }
@@ -153,13 +151,6 @@ else if (!Modifier.isAbstract(access) && node.getBody() == null) {
153151
private class InterfaceMemberSignatureVisitor extends SignatureVisitor {
154152

155153
@Override public Void visit(MethodDeclaration node) {
156-
int access = node.getAccessFlags();
157-
if (Modifier.isProtected(access) || Modifier.isPrivate(access) || Modifier.isStatic(access) ||
158-
Modifier.isStrict(access) || Modifier.isNative(access) || Modifier.isSynchronized(access) ||
159-
Modifier.isFinal(access)) {
160-
setErrorStrings(node, node.getName());
161-
throw new ExecutionError("interface.method.modifier", node);
162-
}
163154
super.visit(node);
164155
if (node.getBody() != null) {
165156
setErrorStrings(node, node.getName());
@@ -169,11 +160,6 @@ private class InterfaceMemberSignatureVisitor extends SignatureVisitor {
169160
}
170161

171162
@Override public Void visit(FieldDeclaration node) {
172-
int access = node.getAccessFlags();
173-
if (Modifier.isProtected(access) || Modifier.isPrivate(access)) {
174-
setErrorStrings(node, node.getName());
175-
throw new ExecutionError("interface.field.modifier", node);
176-
}
177163
super.visit(node);
178164
if (node.getInitializer() == null) {
179165
setErrorStrings(node, node.getName());
@@ -217,12 +203,14 @@ private class BodyVisitor extends AbstractVisitor<Void> {
217203
DJConstructor k = getConstructor(node);
218204
TypeContext sigContext = new FunctionSignatureContext(_context, k);
219205
TypeContext bodyContext = new FunctionContext(sigContext, k);
206+
ExpressionChecker callChecker = new ExpressionChecker(bodyContext, _opt);
220207
ConstructorCall call = node.getConstructorCall();
221-
if (call == null) { call = new ConstructorCall(null, null, true); }
222-
new ExpressionChecker(bodyContext, _opt).check(call);
208+
if (call != null) { callChecker.checkConstructorCall(call); }
223209
for (Node n : node.getStatements()) {
224210
bodyContext = n.acceptVisitor(new StatementChecker(bodyContext, _opt));
225211
}
212+
// if the call is implicit, check it *after* checking the body (better error messages this way)
213+
if (call == null) { callChecker.checkConstructorCall(new ConstructorCall(null, null, true)); }
226214
return null;
227215
}
228216

dynamicjava/src/edu/rice/cs/dynamicjava/interpreter/CompositeException.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import java.io.PrintWriter;
44

5+
import koala.dynamicjava.tree.SourceInfo;
6+
57
import edu.rice.cs.plt.iter.IterUtil;
68
import edu.rice.cs.plt.iter.SizedIterable;
79

@@ -16,7 +18,7 @@ public CompositeException(Iterable<? extends InterpreterException> exceptions) {
1618
public void printUserMessage(PrintWriter out) {
1719
out.println(_exceptions.size() + " errors:");
1820
for (InterpreterException e : _exceptions) {
19-
if (e instanceof CheckerException) { out.println(((CheckerException) e).getSourceInfo()); }
21+
if (e instanceof SourceInfo.Wrapper) { out.println(((SourceInfo.Wrapper) e).getSourceInfo()); }
2022
else { out.println("[Unknown location]"); }
2123
e.printUserMessage(out);
2224
}

dynamicjava/src/edu/rice/cs/dynamicjava/interpreter/ExpressionChecker.java

Lines changed: 89 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,77 @@ private Iterable<Type> checkTypeNameList(Iterable<? extends TypeName> l) {
167167
return new TypeNameChecker(context, opt).checkList(l);
168168
}
169169

170+
/**
171+
* Handle a valid constructor call: one that appears as the first line of a constructor.
172+
* ConstructorCalls handled via {@link #check(Expression)} will always be treated as errors.
173+
*/
174+
public void checkConstructorCall(ConstructorCall node) {
175+
if (node.getExpression() != null) {
176+
throw new ExecutionError("not.implemented", node);
177+
}
178+
179+
Iterable<? extends Expression> args = node.getArguments();
180+
checkList(args);
181+
182+
// TODO: implement explicit type arguments in constructor calls
183+
Iterable<Type> targs = IterUtil.empty();
184+
185+
Type type;
186+
if (node.isSuper()) { type = context.getSuperType(ts); }
187+
else { type = SymbolUtil.thisType(context.getThis()); }
188+
if (type == null) {
189+
throw new IllegalArgumentException("Can't check a ConstructorCall in this context");
190+
}
191+
192+
try {
193+
ConstructorInvocation inv = ts.lookupConstructor(type, targs, args, Option.<Type>none());
194+
195+
// TODO: Check accessibility of constructor
196+
// Note that super constructor calls *have to* be accessible, even if accessibility
197+
// checking is turned off -- a call to a private constructor cannot be compiled
198+
// in a way that it will run successfully (since constructor calls are the only code
199+
// that is directly compiled rather than being interpreted, we don't have this problem
200+
// elsewhere)
201+
checkThrownExceptions(inv.thrown(), node);
202+
node.setArguments(CollectUtil.makeList(inv.args()));
203+
setConstructor(node, inv.constructor());
204+
setType(node, type);
205+
}
206+
catch (InvalidTypeArgumentException e) {
207+
throw new ExecutionError("type.argument", node);
208+
}
209+
catch (TypeSystemException e) {
210+
setErrorStrings(node, ts.userRepresentation(type), nodeTypesString(args));
211+
throw new ExecutionError("no.such.constructor", node);
212+
}
213+
}
214+
215+
/** Verify that the thrown exceptions are expected in this context. */
216+
private void checkThrownExceptions(Iterable<? extends Type> thrownTypes, Node node) {
217+
Iterable<Type> allowed = IterUtil.compose(TypeSystem.RUNTIME_EXCEPTION,
218+
context.getDeclaredThrownTypes());
219+
for (Type thrown : thrownTypes) {
220+
if (ts.isAssignable(TypeSystem.EXCEPTION, thrown)) {
221+
boolean valid = false;
222+
for (Type t : allowed) {
223+
if (ts.isAssignable(t, thrown)) { valid = true; break; }
224+
}
225+
if (!valid) {
226+
setErrorStrings(node, ts.userRepresentation(thrown));
227+
throw new ExecutionError("uncaught.exception", node);
228+
}
229+
}
230+
}
231+
}
232+
233+
private String nodeTypesString(Iterable<? extends Node> nodes) {
234+
Lambda<Node, String> typeString = new Lambda<Node, String>() {
235+
public String value(Node n) { return ts.userRepresentation(getType(n)); }
236+
};
237+
return IterUtil.toString(IterUtil.map(nodes, typeString), "", ", ", "");
238+
}
239+
240+
170241

171242
private class ExpressionVisitor extends AbstractVisitor<Type> implements Lambda<Expression, Type> {
172243

@@ -177,13 +248,6 @@ private class ExpressionVisitor extends AbstractVisitor<Type> implements Lambda<
177248

178249
public Type value(Expression e) { return e.acceptVisitor(this); }
179250

180-
private String nodeTypesString(Iterable<? extends Node> nodes) {
181-
Lambda<Node, String> typeString = new Lambda<Node, String>() {
182-
public String value(Node n) { return ts.userRepresentation(getType(n)); }
183-
};
184-
return IterUtil.toString(IterUtil.map(nodes, typeString), "", ", ", "");
185-
}
186-
187251

188252
@Override public Type visit(AmbiguousName node) {
189253
Node resolved = resolveAmbiguousName(node);
@@ -387,20 +451,6 @@ else if (ts.containsClass(classType, memberName.image())) {
387451
*/
388452
@Override public Type visit(ObjectFieldAccess node) {
389453
Expression receiver = node.getExpression();
390-
if (receiver instanceof AmbiguousName) {
391-
Node resolved = resolveAmbiguousName((AmbiguousName) receiver);
392-
if (resolved instanceof ReferenceTypeName) {
393-
// this is actually a StaticFieldAccess
394-
Expression translation =
395-
new StaticFieldAccess((ReferenceTypeName) resolved, node.getFieldName(), node.getSourceInfo());
396-
translation.acceptVisitor(this);
397-
setTranslation(node, translation);
398-
setVariableType(node, getVariableType(translation));
399-
return setType(node, getType(translation));
400-
}
401-
else { receiver = (Expression) resolved; }
402-
}
403-
404454
Type receiverT = check(receiver);
405455
try {
406456
ObjectFieldReference ref = ts.lookupField(receiver, node.getFieldName());
@@ -471,8 +521,8 @@ else if (ts.containsClass(classType, memberName.image())) {
471521
* @return The type of the expression
472522
*/
473523
@Override public Type visit(SimpleMethodCall node) {
474-
Iterable<? extends Expression> args = IterUtil.empty();
475-
if (node.getArguments() != null) { args = node.getArguments(); checkList(args); }
524+
Iterable<? extends Expression> args = node.getArguments();
525+
checkList(args);
476526

477527
Iterable<Type> targs = IterUtil.empty();
478528

@@ -554,8 +604,8 @@ else if (ts.containsClass(classType, memberName.image())) {
554604

555605
Type receiverT = check(receiver);
556606

557-
Iterable<? extends Expression> args = IterUtil.empty();
558-
if (node.getArguments() != null) { args = node.getArguments(); checkList(args); }
607+
Iterable<? extends Expression> args = node.getArguments();
608+
checkList(args);
559609

560610
Iterable<Type> targs = IterUtil.empty();
561611
if (node instanceof PolymorphicObjectMethodCall) {
@@ -594,8 +644,8 @@ else if (ts.containsClass(classType, memberName.image())) {
594644
throw new ExecutionError("super.undefined", node);
595645
}
596646

597-
Iterable<? extends Expression> args = IterUtil.empty();
598-
if (node.getArguments() != null) { args = node.getArguments(); checkList(args); }
647+
Iterable<? extends Expression> args = node.getArguments();
648+
checkList(args);
599649

600650
Iterable<Type> targs = IterUtil.empty();
601651
if (node instanceof PolymorphicSuperMethodCall) {
@@ -632,8 +682,8 @@ else if (ts.containsClass(classType, memberName.image())) {
632682
@Override public Type visit(StaticMethodCall node) {
633683
Type t = checkTypeName(node.getMethodType());
634684

635-
Iterable<? extends Expression> args = IterUtil.empty();
636-
if (node.getArguments() != null) { args = node.getArguments(); checkList(args); }
685+
Iterable<? extends Expression> args = node.getArguments();
686+
checkList(args);
637687

638688
Iterable<Type> targs = IterUtil.empty();
639689
if (node instanceof PolymorphicStaticMethodCall) {
@@ -747,8 +797,8 @@ private void addRuntimeCheck(Node node, Type expectedType, Type declaredActualTy
747797
throw new ExecutionError("allocation.type", node);
748798
}
749799

750-
Iterable<? extends Expression> args = IterUtil.empty();
751-
if (node.getArguments() != null) { args = node.getArguments(); checkList(args); }
800+
Iterable<? extends Expression> args = node.getArguments();
801+
checkList(args);
752802

753803
Iterable<Type> targs = IterUtil.empty();
754804
if (node instanceof PolymorphicSimpleAllocation) {
@@ -783,8 +833,8 @@ private void addRuntimeCheck(Node node, Type expectedType, Type declaredActualTy
783833
throw new ExecutionError("allocation.type", node);
784834
}
785835

786-
Iterable<? extends Expression> args = IterUtil.empty();
787-
if (node.getArguments() != null) { args = node.getArguments(); checkList(args); }
836+
Iterable<? extends Expression> args = node.getArguments();
837+
checkList(args);
788838

789839
Iterable<Type> targs = IterUtil.empty();
790840
if (node instanceof PolymorphicAnonymousAllocation) {
@@ -838,8 +888,8 @@ private void addRuntimeCheck(Node node, Type expectedType, Type declaredActualTy
838888
throw new ExecutionError("allocation.type", node);
839889
}
840890

841-
Iterable<? extends Expression> args = IterUtil.empty();
842-
if (node.getArguments() != null) { args = node.getArguments(); checkList(args); }
891+
Iterable<? extends Expression> args = node.getArguments();
892+
checkList(args);
843893

844894
Iterable<Type> targs = IterUtil.empty();
845895
if (node instanceof PolymorphicInnerAllocation) {
@@ -891,8 +941,8 @@ private void addRuntimeCheck(Node node, Type expectedType, Type declaredActualTy
891941
}
892942
setSuperType(node, t);
893943

894-
Iterable<? extends Expression> args = IterUtil.empty();
895-
if (node.getArguments() != null) { args = node.getArguments(); checkList(args); }
944+
Iterable<? extends Expression> args = node.getArguments();
945+
checkList(args);
896946

897947
Iterable<Type> targs = IterUtil.empty();
898948
if (node instanceof PolymorphicAnonymousInnerAllocation) {
@@ -932,71 +982,11 @@ private void addRuntimeCheck(Node node, Type expectedType, Type declaredActualTy
932982
return setType(node, ts.makeClassType(c));
933983
}
934984

935-
/**
936-
* Visits a ConstructorCall.
937-
* @return The type of this or super.
938-
*/
939985
@Override public Type visit(ConstructorCall node) {
940-
if (node.getExpression() != null) {
941-
throw new ExecutionError("not.implemented", node);
942-
}
943-
944-
Iterable<? extends Expression> args = IterUtil.empty();
945-
if (node.getArguments() != null) { args = node.getArguments(); checkList(args); }
946-
947-
// TODO: implement explict type arguments in constructor calls
948-
Iterable<Type> targs = IterUtil.empty();
949-
950-
Type result;
951-
if (node.isSuper()) { result = context.getSuperType(ts); }
952-
else { result = SymbolUtil.thisType(context.getThis()); }
953-
if (result == null) {
954-
throw new IllegalArgumentException("Can't check a ConstructorCall in this context");
955-
}
956-
957-
try {
958-
ConstructorInvocation inv = ts.lookupConstructor(result, targs, args, expected);
959-
960-
// TODO: Check accessibility of constructor
961-
// Note that super constructor calls *have to* be accessible, even if accessibility
962-
// checking is turned off -- a call to a private constructor cannot be compiled
963-
// in a way that it will run successfully (since constructor calls are the only code
964-
// that is directly compiled rather than being interpreted, we don't have this problem
965-
// elsewhere)
966-
checkThrownExceptions(inv.thrown(), node);
967-
node.setArguments(CollectUtil.makeList(inv.args()));
968-
setConstructor(node, inv.constructor());
969-
return setType(node, result);
970-
}
971-
catch (InvalidTypeArgumentException e) {
972-
throw new ExecutionError("type.argument", node);
973-
}
974-
catch (TypeSystemException e) {
975-
setErrorStrings(node, ts.userRepresentation(result), nodeTypesString(args));
976-
throw new ExecutionError("no.such.constructor", node);
977-
}
978-
}
979-
980-
/** Verify that the thrown exceptions are expected in this context. */
981-
private void checkThrownExceptions(Iterable<? extends Type> thrownTypes, Node node) {
982-
Iterable<Type> allowed = IterUtil.compose(TypeSystem.RUNTIME_EXCEPTION,
983-
context.getDeclaredThrownTypes());
984-
for (Type thrown : thrownTypes) {
985-
if (ts.isAssignable(TypeSystem.EXCEPTION, thrown)) {
986-
boolean valid = false;
987-
for (Type t : allowed) {
988-
if (ts.isAssignable(t, thrown)) { valid = true; break; }
989-
}
990-
if (!valid) {
991-
setErrorStrings(node, ts.userRepresentation(thrown));
992-
throw new ExecutionError("uncaught.exception", node);
993-
}
994-
}
995-
}
986+
throw new ExecutionError("constructor.call", node);
996987
}
997988

998-
999-
989+
1000990
/**
1001991
* Visits an ArrayAccess. JLS 15.13.
1002992
* @return The type of the expression

0 commit comments

Comments
 (0)