slcom/slangc/model/ExpressionModel.sauce

314 lines
11 KiB
Plaintext

package slangc.model;
import slangc.api.BytecodeInstructionWriter;
import slangc.api.Reporter;
import slangc.bytecode.TypeSignature;
import slangc.model.clauses.Arguments;
import slangc.model.expressions.*;
import slangc.parser.Branch;
import slangc.parser.ErrorType;
import slangc.parser.Node;
import slangc.parser.NodeType;
import slangc.parser.NoteAnnotation;
public abstract class ExpressionModel extends StatementOrExpression implements ExpressionOwner {
ExpressionOwner owner;
Node source;
ExpressionResult resolvedResult;
public ExpressionModel(ExpressionOwner owner, Node source) {
this.owner = owner;
this.source = source;
}
public ExpressionOwner getOwner() {
return owner;
}
public Node getSource() {
return source;
}
public static ExpressionModel construct(ExpressionOwner owner, Node source) {
switch (source.getNodeType()) {
case NodeType.BRACED_EXPRESSION:
return construct(owner, ((Branch) source).getSubnode(1));
case NodeType.INTEGER_LITERAL_EXPRESSION:
case NodeType.CHAR_LITERAL_EXPRESSION:
case NodeType.BOOLEAN_LITERAL_EXPRESSION:
case NodeType.STRING_LITERAL_EXPRESSION:
case NodeType.FLOAT_LITERAL_EXPRESSION:
case NodeType.NULL_LITERAL_EXPRESSION:
return new LiteralExpression(owner, source);
case NodeType.ADDITIVE_EXPRESSION:
case NodeType.MULTIPLICATIVE_EXPRESSION:
case NodeType.COMPARISON_EXPRESSION:
case NodeType.LOGICAL_EXPRESSION:
case NodeType.SHIFT_EXPRESSION:
case NodeType.EQUALITY_EXPRESSION:
case NodeType.BITWISE_AND_EXPRESSION:
case NodeType.BITWISE_XOR_EXPRESSION:
case NodeType.BITWISE_OR_EXPRESSION:
case NodeType.LOGICAL_AND_EXPRESSION:
case NodeType.LOGICAL_OR_EXPRESSION:
return new BinaryExpression(owner, source);
case NodeType.CONDITIONAL_EXPRESSION:
return new ConditionalExpression(owner, source);
case NodeType.REFERENCE_EXPRESSION:
return new ReferenceExpression(owner, source);
case NodeType.GENERIC_REFERENCE_EXPRESSION:
return new GenericReferenceExpression(owner, source);
case NodeType.THIS_EXPRESSION:
return new ThisExpression(owner, source);
case NodeType.SUBREFERENCE_EXPRESSION:
if (((Branch)source).getSubnode(0).getNodeType() == NodeType.SUPER) {
return new SuperReferenceExpression(owner, source);
} else {
return new SubreferenceExpression(owner, source);
}
case NodeType.ASSIGNMENT_EXPRESSION:
return new AssignmentExpression(owner, source);
case NodeType.UNARY_EXPRESSION:
return new UnaryExpression(owner, source);
case NodeType.COUNT_EXPRESSION:
return new CountExpression(owner, source);
case NodeType.CAST_EXPRESSION:
return new CastExpression(owner, source);
case NodeType.INSTANCEOF_EXPRESSION:
return new InstanceofExpression(owner, source);
case NodeType.TYPE_EXPRESSION:
return new TypeExpression(owner, source);
case NodeType.OUTER_THIS_EXPRESSION:
return new OuterThisExpression(owner, source);
case NodeType.NEW_OBJECT_EXPRESSION:
return new NewObjectExpression(owner, source);
case NodeType.NEW_CLASS_EXPRESSION:
return new NewClassExpression(owner, source);
case NodeType.NEW_CLEARED_ARRAY_EXPRESSION:
return new NewClearedArrayExpression(owner, source);
case NodeType.NEW_INITIALISED_ARRAY_EXPRESSION:
return new NewInitialisedArrayExpression(owner, source);
case NodeType.SUPER_CONSTRUCTOR_CALL_EXPRESSION:
return new SuperConstructorCallExpression(owner, source);
case NodeType.THIS_CONSTRUCTOR_CALL_EXPRESSION:
return new ThisConstructorCallExpression(owner, source);
case NodeType.NORMAL_METHOD_CALL_EXPRESSION:
return new NormalMethodCallExpression(owner, source);
case NodeType.AUTOMATIC_METHOD_CALL_EXPRESSION:
return new AutomaticMethodCallExpression(owner, source);
case NodeType.SUPER_METHOD_CALL_EXPRESSION:
return new SuperMethodCallExpression(owner, source);
case NodeType.THIS_METHOD_CALL_EXPRESSION:
return new ThisMethodCallExpression(owner, source);
case NodeType.ARRAY_INDEX_EXPRESSION:
return new ArrayIndexExpression(owner, source);
case NodeType.ARRAY_INITIALISER:
return new ArrayInitialiserExpression(owner, source);
default:
return new UnrecognisedExpression(owner, source);
}
}
public void dump(Reporter reporter, String indent, String incr) {
reporter.note("DUMP", indent + incr + "TODO: dump " + Type.of(this));
dumpResolved(reporter, indent + incr, incr);
}
public void dumpResolved(Reporter reporter, String indent, String incr) {
if (isResolved()) {
if (hasTargetMethod()) {
reporter.note("DUMP", indent + incr + "Target method is " + getTargetMethod());
}
reporter.note("DUMP", indent + incr + "Result is " + getResult());
}
}
public InnerTypeScope getTypeScope() {
// TODO: Better interface support
if (getOwner() instanceof ExpressionModel) {
return ((ExpressionModel)getOwner()).getTypeScope();
}
return getOwner().getTypeScope();
}
public TypeModel resolveType(Node subnode) {
// TODO: Better interface support
if (getOwner() instanceof ExpressionModel) {
return ((ExpressionModel)getOwner()).resolveType(subnode);
}
return getOwner().resolveType(subnode);
}
public MemberModel getMethodOrField() {
// TODO: Better interface support
if (getOwner() instanceof ExpressionModel) {
return ((ExpressionModel)getOwner()).getMethodOrField();
}
return getOwner().getMethodOrField();
}
public Named lookupSimpleName(String name) {
// TODO: Better interface support
if (getOwner() instanceof ExpressionModel) {
return ((ExpressionModel)getOwner()).lookupSimpleName(name);
}
return getOwner().lookupSimpleName(name);
}
public MethodModel[] lookupSimpleMethod(String name) {
// TODO: Better interface support
if (getOwner() instanceof ExpressionModel) {
return ((ExpressionModel)getOwner()).lookupSimpleMethod(name);
}
return getOwner().lookupSimpleMethod(name);
}
//@Override
public TypeModel getExpectedResult(ExpressionModel e) {
return null;
}
/**
* Used as a default for getSubexpressions() to avoid creating empty arrays.
*/
public static final ExpressionModel[] NO_SUBEXPRESSIONS = new ExpressionModel[0];
public abstract ExpressionModel[] getSubexpressions();
protected int resolveSubexpressions() {
int nresolved = 0;
ExpressionModel[] exprs = getSubexpressions();
for (int i = 0; i < exprs.length; i++) {
nresolved += exprs[i].resolveExpressions();
}
return nresolved;
}
@Override
public final int resolveExpressions() {
if (isResolved()) {
return 0;
}
int nresolved = resolveSubexpressions();
/** If subexpressions resulted in an error, return early to avoid making concentric nonsense errors. */
if (getSource().countErrorsRecursively() > 0) {
return nresolved;
}
resolvedResult = resolveResult();
if (resolvedResult == null) {
/* For consistency, failed resolutions logically resolve to an invalid result. */
resolvedResult = ExpressionResult.INVALID;
}
if (resolvedResult.getKind() == ExpressionResult.Kind.INVALID) {
if (getSource() == null) {
throw new Error("Internal error: Failed to resolve synthetic expression " + this);
}
if (getSource() != null && getSource().countErrorsRecursively() == 0) {
getSource().annotate(ErrorType.INTERNAL_ERROR, "Compiler failed to derive any result information in " + Type.of(this));
}
} else {
nresolved++;
}
return nresolved;
}
/**
* This should only usually be called once by resolveExpressions(). Before the first call,
* any subexpressions are resolved recursively. After the first call,
* the expression result is stored by ExpressionModel and accessible from getResult().
*
* @return Either an ExpressionResult instance holding the resolved information
* about the expression's result, or null (which will be taken as an invalid result).
*/
//protected abstract ExpressionResult resolveResult();
protected ExpressionResult resolveResult() {return null;}
public boolean isResolved() {
return resolvedResult != null;
}
public ExpressionResult getResult() {
if (!isResolved()) {
throw new Error("Attempting to get result of unresolved expression!");
}
return resolvedResult;
}
public SystemModel getSystem() {
return getOwner().getMethodOrField().getOwner().getPackage().getSystem();
}
public boolean hasTargetMethod() {
return false;
}
public MethodModel getTargetMethod() {
throw new Error("Can't get target method of a " + Type.of(this));
}
/**
* Attempts to select the best applicable method from a list of available options, using
* the static methods of MethodModel to sort through them. The reason for doing the final
* selection here is so that we can report errors in the right place and in a consistent way.
*
* <p/>
* If a single "best" method is found, it is returned. Otherwise (if zero methods match or
* if multiple match and we can't select a best one from them) an error is reported and
* null is returned.
*
* @param availableMethods
* @param arguments
* @return
*/
public MethodModel bestTargetMethod(MethodModel[] availableMethods, Arguments arguments) {
MethodModel[] bestChoices = //MethodModel.findApplicableMethods(availableMethods, arguments);
MethodModel.bestApplicableMethods(availableMethods, arguments, false);
/* If we can't find a relevant method without varargs, only then try varargs. */
if (bestChoices.length != 1) {
MethodModel[] newChoices = MethodModel.bestApplicableMethods(availableMethods, arguments, true);
if (newChoices.length == 1) {
return newChoices[0];
}
}
if (bestChoices.length == 1) {
return bestChoices[0];
} else if (bestChoices.length > 1) {
getSource().annotate(ErrorType.INTERNAL_ERROR, "Ambiguous method invocation");
for (int i = 0; i < bestChoices.length; i++) {
getSource().annotate(new NoteAnnotation("Could be referring to " + bestChoices[i]));
}
return null;
} else { // No choices
getSource().annotate(ErrorType.INTERNAL_ERROR, "No matching method for " + arguments.resultString());
if (availableMethods.length == 0) {
getSource().annotate(new NoteAnnotation("There appear to be no such methods to select from"));
} else {
for (int i = 0; i < availableMethods.length; i++) {
getSource().annotate(new NoteAnnotation("Failed to match " + availableMethods[i]));
}
}
return null;
}
}
public abstract TypeSignature innerGenerate(BytecodeInstructionWriter w);
public final TypeSignature generate(BytecodeInstructionWriter w) {
w.pushSource(getSource());
TypeSignature result = innerGenerate(w);
w.popSource();
if (result == null) {
result = TypeSignature.VOID;
}
return result;
}
public void generateStore(BytecodeInstructionWriter w, TypeSignature storing) {
w.genError("TODO: generateStore for " + Type.of(this));
}
}