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. * *
* 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)); } }