Special instructions added for calls and other constructs
This commit is contained in:
@@ -19,7 +19,11 @@ package org.jetbrains.jet.lang.cfg;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode;
|
||||
import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -82,7 +86,24 @@ public interface JetControlFlowBuilder {
|
||||
|
||||
// Reading values
|
||||
void loadUnit(@NotNull JetExpression expression);
|
||||
void read(@NotNull JetElement element);
|
||||
void loadConstant(@NotNull JetExpression expression, @Nullable CompileTimeConstant<?> constant);
|
||||
void createAnonymousObject(@NotNull JetObjectLiteralExpression expression);
|
||||
void loadStringTemplate(@NotNull JetStringTemplateExpression expression);
|
||||
|
||||
void readThis(@NotNull JetExpression expression, @Nullable ReceiverParameterDescriptor parameterDescriptor);
|
||||
void readVariable(@NotNull JetExpression expression, @Nullable VariableDescriptor variableDescriptor);
|
||||
|
||||
void call(@NotNull JetExpression expression, @NotNull ResolvedCall<?> resolvedCall);
|
||||
|
||||
enum PredefinedOperation {
|
||||
AND,
|
||||
OR,
|
||||
NOT_NULL_ASSERTION
|
||||
}
|
||||
void predefinedOperation(@NotNull JetExpression expression, @Nullable PredefinedOperation operation);
|
||||
|
||||
void compilationError(@NotNull JetElement element, @NotNull String message);
|
||||
|
||||
void write(@NotNull JetElement assignment, @NotNull JetElement lValue);
|
||||
|
||||
// Other
|
||||
|
||||
@@ -19,7 +19,11 @@ package org.jetbrains.jet.lang.cfg;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode;
|
||||
import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -27,13 +31,48 @@ public class JetControlFlowBuilderAdapter implements JetControlFlowBuilder {
|
||||
protected JetControlFlowBuilder builder;
|
||||
|
||||
@Override
|
||||
public void read(@NotNull JetElement element) {
|
||||
builder.read(element);
|
||||
public void loadUnit(@NotNull JetExpression expression) {
|
||||
builder.loadUnit(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadUnit(@NotNull JetExpression expression) {
|
||||
builder.loadUnit(expression);
|
||||
public void loadConstant(@NotNull JetExpression expression, @Nullable CompileTimeConstant<?> constant) {
|
||||
builder.loadConstant(expression, constant);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createAnonymousObject(@NotNull JetObjectLiteralExpression expression) {
|
||||
builder.createAnonymousObject(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadStringTemplate(@NotNull JetStringTemplateExpression expression) {
|
||||
builder.loadStringTemplate(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readThis(@NotNull JetExpression expression, @Nullable ReceiverParameterDescriptor parameterDescriptor) {
|
||||
builder.readThis(expression, parameterDescriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readVariable(@NotNull JetExpression expression, @Nullable VariableDescriptor variableDescriptor) {
|
||||
builder.readVariable(expression, variableDescriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void call(@NotNull JetExpression expression, @NotNull ResolvedCall<?> resolvedCall) {
|
||||
builder.call(expression, resolvedCall);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void predefinedOperation(@NotNull JetExpression expression, @Nullable PredefinedOperation operation) {
|
||||
builder.predefinedOperation(expression, operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compilationError(@NotNull JetElement element, @NotNull String message) {
|
||||
builder.compilationError(element, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -26,21 +26,35 @@ import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowInstructionsGenerator
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.LocalFunctionDeclarationInstruction;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.PseudocodeImpl;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastReceiver;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.calls.util.ExpressionAsFunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.resolve.constants.BooleanValue;
|
||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstantResolver;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ThisReceiver;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.TransientReceiver;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||
import org.jetbrains.jet.lexer.JetToken;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.jet.lang.cfg.JetControlFlowBuilder.PredefinedOperation.*;
|
||||
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
|
||||
|
||||
public class JetControlFlowProcessor {
|
||||
@@ -153,8 +167,6 @@ public class JetControlFlowProcessor {
|
||||
|
||||
@Override
|
||||
public void visitParenthesizedExpression(@NotNull JetParenthesizedExpression expression) {
|
||||
builder.read(expression);
|
||||
|
||||
JetExpression innerExpression = expression.getExpression();
|
||||
if (innerExpression != null) {
|
||||
generateInstructions(innerExpression, inCondition);
|
||||
@@ -163,8 +175,6 @@ public class JetControlFlowProcessor {
|
||||
|
||||
@Override
|
||||
public void visitAnnotatedExpression(@NotNull JetAnnotatedExpression expression) {
|
||||
builder.read(expression);
|
||||
|
||||
JetExpression baseExpression = expression.getBaseExpression();
|
||||
if (baseExpression != null) {
|
||||
generateInstructions(baseExpression, inCondition);
|
||||
@@ -173,17 +183,26 @@ public class JetControlFlowProcessor {
|
||||
|
||||
@Override
|
||||
public void visitThisExpression(@NotNull JetThisExpression expression) {
|
||||
builder.read(expression);
|
||||
ResolvedCall<?> resolvedCall = getResolvedCall(expression);
|
||||
builder.readThis(expression, resolvedCall == null ? null : (ReceiverParameterDescriptor) resolvedCall.getResultingDescriptor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitConstantExpression(@NotNull JetConstantExpression expression) {
|
||||
builder.read(expression);
|
||||
CompileTimeConstant<?> constant = trace.get(BindingContext.COMPILE_TIME_VALUE, expression);
|
||||
builder.loadConstant(expression, constant);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSimpleNameExpression(@NotNull JetSimpleNameExpression expression) {
|
||||
builder.read(expression);
|
||||
ResolvedCall<?> resolvedCall = getResolvedCall(expression);
|
||||
if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
|
||||
VariableAsFunctionResolvedCall variableAsFunctionResolvedCall = (VariableAsFunctionResolvedCall) resolvedCall;
|
||||
generateCall(expression, variableAsFunctionResolvedCall.getVariableCall());
|
||||
}
|
||||
else {
|
||||
generateCall(expression);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -204,7 +223,8 @@ public class JetControlFlowProcessor {
|
||||
|
||||
@SuppressWarnings("SuspiciousMethodCalls") @Override
|
||||
public void visitBinaryExpression(@NotNull JetBinaryExpression expression) {
|
||||
IElementType operationType = expression.getOperationReference().getReferencedNameElementType();
|
||||
JetSimpleNameExpression operationReference = expression.getOperationReference();
|
||||
IElementType operationType = operationReference.getReferencedNameElementType();
|
||||
JetExpression right = expression.getRight();
|
||||
if (operationType == JetTokens.ANDAND) {
|
||||
generateInstructions(expression.getLeft(), true);
|
||||
@@ -215,7 +235,7 @@ public class JetControlFlowProcessor {
|
||||
}
|
||||
builder.bindLabel(resultLabel);
|
||||
if (!inCondition) {
|
||||
builder.read(expression);
|
||||
builder.predefinedOperation(expression, AND);
|
||||
}
|
||||
}
|
||||
else if (operationType == JetTokens.OROR) {
|
||||
@@ -227,51 +247,33 @@ public class JetControlFlowProcessor {
|
||||
}
|
||||
builder.bindLabel(resultLabel);
|
||||
if (!inCondition) {
|
||||
builder.read(expression);
|
||||
builder.predefinedOperation(expression, OR);
|
||||
}
|
||||
}
|
||||
else if (operationType == JetTokens.EQ) {
|
||||
JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft());
|
||||
if (right != null) {
|
||||
generateInstructions(right, false);
|
||||
}
|
||||
if (left instanceof JetSimpleNameExpression) {
|
||||
builder.write(expression, left);
|
||||
}
|
||||
else if (left instanceof JetArrayAccessExpression) {
|
||||
JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left;
|
||||
visitAssignToArrayAccess(expression, arrayAccessExpression);
|
||||
}
|
||||
else if (left instanceof JetQualifiedExpression) {
|
||||
JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) left;
|
||||
generateInstructions(qualifiedExpression.getReceiverExpression(), false);
|
||||
generateInstructions(expression.getOperationReference(), false);
|
||||
builder.write(expression, left);
|
||||
}
|
||||
else {
|
||||
builder.unsupported(expression); // TODO
|
||||
}
|
||||
visitAssignment(expression.getLeft(), expression);
|
||||
}
|
||||
else if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) {
|
||||
JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft());
|
||||
if (left != null) {
|
||||
generateInstructions(left, false);
|
||||
if (generateCall(operationReference)) {
|
||||
ResolvedCall<?> resolvedCall = getResolvedCall(operationReference);
|
||||
assert resolvedCall != null : "Generation succeeded, but no call is found: " + expression.getText();
|
||||
CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
|
||||
Name assignMethodName = OperatorConventions.getNameForOperationSymbol((JetToken) expression.getOperationToken());
|
||||
if (!descriptor.getName().equals(assignMethodName)) {
|
||||
// plus() called, assignment needed
|
||||
visitAssignment(expression.getLeft(), expression);
|
||||
}
|
||||
}
|
||||
if (right != null) {
|
||||
generateInstructions(right, false);
|
||||
}
|
||||
if (left instanceof JetSimpleNameExpression || left instanceof JetArrayAccessExpression) {
|
||||
generateInstructions(expression.getOperationReference(), false);
|
||||
builder.write(expression, left);
|
||||
}
|
||||
else if (left != null) {
|
||||
builder.unsupported(expression); // TODO
|
||||
else {
|
||||
generateBothArguments(expression);
|
||||
}
|
||||
}
|
||||
else if (operationType == JetTokens.ELVIS) {
|
||||
builder.read(expression);
|
||||
generateInstructions(expression.getLeft(), false);
|
||||
generateInstructions(expression.getOperationReference(), false);
|
||||
generateInstructions(operationReference, false);
|
||||
Label afterElvis = builder.createUnboundLabel();
|
||||
builder.jumpOnTrue(afterElvis);
|
||||
if (right != null) {
|
||||
@@ -280,22 +282,60 @@ public class JetControlFlowProcessor {
|
||||
builder.bindLabel(afterElvis);
|
||||
}
|
||||
else {
|
||||
generateInstructions(expression.getLeft(), false);
|
||||
if (right != null) {
|
||||
generateInstructions(right, false);
|
||||
if (!generateCall(operationReference)) {
|
||||
generateBothArguments(expression);
|
||||
}
|
||||
generateInstructions(expression.getOperationReference(), false);
|
||||
builder.read(expression);
|
||||
}
|
||||
}
|
||||
|
||||
private void visitAssignToArrayAccess(JetBinaryExpression expression, JetArrayAccessExpression arrayAccessExpression) {
|
||||
for (JetExpression index : arrayAccessExpression.getIndexExpressions()) {
|
||||
generateInstructions(index, false);
|
||||
private void generateBothArguments(JetBinaryExpression expression) {
|
||||
JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft());
|
||||
if (left != null) {
|
||||
generateInstructions(left, false);
|
||||
}
|
||||
JetExpression right = expression.getRight();
|
||||
if (right != null) {
|
||||
generateInstructions(right, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void visitAssignment(JetExpression lhs, JetExpression parentExpression) {
|
||||
JetExpression left = JetPsiUtil.deparenthesize(lhs);
|
||||
if (left == null) {
|
||||
builder.compilationError(lhs, "No lValue in assignment");
|
||||
return;
|
||||
}
|
||||
if (left instanceof JetSimpleNameExpression) {
|
||||
// Do nothing, only record write below
|
||||
}
|
||||
else if (left instanceof JetArrayAccessExpression) {
|
||||
generateArrayAccess((JetArrayAccessExpression) left);
|
||||
}
|
||||
else if (left instanceof JetQualifiedExpression) {
|
||||
// read the receiver
|
||||
generateInstructions(((JetQualifiedExpression) left).getReceiverExpression(), false);
|
||||
}
|
||||
else if (left instanceof JetProperty) {
|
||||
// do nothing, just write below
|
||||
}
|
||||
else {
|
||||
builder.unsupported(parentExpression); // TODO
|
||||
}
|
||||
|
||||
VariableDescriptor descriptor = BindingContextUtils.extractVariableDescriptorIfAny(trace.getBindingContext(), left, false);
|
||||
if (descriptor != null) {
|
||||
builder.write(parentExpression, left);
|
||||
}
|
||||
}
|
||||
|
||||
private void generateArrayAccess(JetArrayAccessExpression arrayAccessExpression) {
|
||||
if (!generateCall(arrayAccessExpression)) {
|
||||
for (JetExpression index : arrayAccessExpression.getIndexExpressions()) {
|
||||
generateInstructions(index, false);
|
||||
}
|
||||
|
||||
generateInstructions(arrayAccessExpression.getArrayExpression(), false);
|
||||
}
|
||||
generateInstructions(arrayAccessExpression.getArrayExpression(), false);
|
||||
generateInstructions(expression.getOperationReference(), false);
|
||||
builder.write(expression, arrayAccessExpression); // TODO : ???
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -308,16 +348,20 @@ public class JetControlFlowProcessor {
|
||||
String referencedName = operationSign.getReferencedName();
|
||||
visitLabeledExpression(referencedName.substring(1), baseExpression);
|
||||
}
|
||||
else {
|
||||
else if (JetTokens.EXCLEXCL == operationType) {
|
||||
generateInstructions(baseExpression, false);
|
||||
generateInstructions(operationSign, false);
|
||||
builder.predefinedOperation(expression, NOT_NULL_ASSERTION);
|
||||
}
|
||||
else {
|
||||
if (!generateCall(expression.getOperationReference())) {
|
||||
generateInstructions(baseExpression, false);
|
||||
}
|
||||
|
||||
boolean incrementOrDecrement = isIncrementOrDecrement(operationType);
|
||||
if (incrementOrDecrement) {
|
||||
builder.write(expression, baseExpression);
|
||||
// We skip dup's and other subtleties here
|
||||
visitAssignment(baseExpression, expression);
|
||||
}
|
||||
|
||||
builder.read(expression);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,7 +397,7 @@ public class JetControlFlowProcessor {
|
||||
}
|
||||
builder.bindLabel(resultLabel);
|
||||
}
|
||||
|
||||
|
||||
private class FinallyBlockGenerator {
|
||||
private final JetFinallySection finallyBlock;
|
||||
private Label startFinally = null;
|
||||
@@ -382,7 +426,6 @@ public class JetControlFlowProcessor {
|
||||
|
||||
@Override
|
||||
public void visitTryExpression(@NotNull JetTryExpression expression) {
|
||||
builder.read(expression);
|
||||
JetFinallySection finallyBlock = expression.getFinallyBlock();
|
||||
final FinallyBlockGenerator finallyBlockGenerator = new FinallyBlockGenerator(finallyBlock);
|
||||
if (finallyBlock != null) {
|
||||
@@ -414,7 +457,6 @@ public class JetControlFlowProcessor {
|
||||
}
|
||||
generateInstructions(expression.getTryBlock(), inCondition);
|
||||
|
||||
Collection<Label> allowDeadLabels = Lists.newArrayList();
|
||||
if (hasCatches) {
|
||||
Label afterCatches = builder.createUnboundLabel("afterCatches");
|
||||
builder.jump(afterCatches);
|
||||
@@ -467,7 +509,6 @@ public class JetControlFlowProcessor {
|
||||
|
||||
@Override
|
||||
public void visitWhileExpression(@NotNull JetWhileExpression expression) {
|
||||
builder.read(expression);
|
||||
LoopInfo loopInfo = builder.enterLoop(expression, null, null);
|
||||
|
||||
builder.bindLabel(loopInfo.getConditionEntryPoint());
|
||||
@@ -498,7 +539,6 @@ public class JetControlFlowProcessor {
|
||||
|
||||
@Override
|
||||
public void visitDoWhileExpression(@NotNull JetDoWhileExpression expression) {
|
||||
builder.read(expression);
|
||||
LoopInfo loopInfo = builder.enterLoop(expression, null, null);
|
||||
|
||||
builder.bindLabel(loopInfo.getBodyEntryPoint());
|
||||
@@ -518,7 +558,6 @@ public class JetControlFlowProcessor {
|
||||
|
||||
@Override
|
||||
public void visitForExpression(@NotNull JetForExpression expression) {
|
||||
builder.read(expression);
|
||||
JetExpression loopRange = expression.getLoopRange();
|
||||
if (loopRange != null) {
|
||||
generateInstructions(loopRange, false);
|
||||
@@ -657,42 +696,32 @@ public class JetControlFlowProcessor {
|
||||
public void visitFunctionLiteralExpression(@NotNull JetFunctionLiteralExpression expression) {
|
||||
JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
|
||||
processLocalDeclaration(functionLiteral);
|
||||
builder.read(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitQualifiedExpression(@NotNull JetQualifiedExpression expression) {
|
||||
generateInstructions(expression.getReceiverExpression(), false);
|
||||
JetExpression selectorExpression = expression.getSelectorExpression();
|
||||
if (selectorExpression != null) {
|
||||
generateInstructions(selectorExpression, false);
|
||||
}
|
||||
builder.read(expression);
|
||||
}
|
||||
|
||||
private void visitCall(JetCallElement call) {
|
||||
for (ValueArgument argument : call.getValueArguments()) {
|
||||
JetExpression argumentExpression = argument.getArgumentExpression();
|
||||
if (argumentExpression != null) {
|
||||
generateInstructions(argumentExpression, false);
|
||||
}
|
||||
}
|
||||
|
||||
for (JetExpression functionLiteral : call.getFunctionLiteralArguments()) {
|
||||
generateInstructions(functionLiteral, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCallExpression(@NotNull JetCallExpression expression) {
|
||||
for (JetTypeProjection typeArgument : expression.getTypeArguments()) {
|
||||
generateInstructions(typeArgument, false);
|
||||
if (!generateCall(expression.getCalleeExpression())) {
|
||||
for (ValueArgument argument : expression.getValueArguments()) {
|
||||
JetExpression argumentExpression = argument.getArgumentExpression();
|
||||
if (argumentExpression != null) {
|
||||
generateInstructions(argumentExpression, false);
|
||||
}
|
||||
}
|
||||
|
||||
for (JetExpression functionLiteral : expression.getFunctionLiteralArguments()) {
|
||||
generateInstructions(functionLiteral, false);
|
||||
}
|
||||
|
||||
generateInstructions(expression.getCalleeExpression(), false);
|
||||
}
|
||||
|
||||
visitCall(expression);
|
||||
|
||||
generateInstructions(expression.getCalleeExpression(), false);
|
||||
builder.read(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -701,7 +730,7 @@ public class JetControlFlowProcessor {
|
||||
JetExpression initializer = property.getInitializer();
|
||||
if (initializer != null) {
|
||||
generateInstructions(initializer, false);
|
||||
builder.write(property, property);
|
||||
visitAssignment(property, property);
|
||||
}
|
||||
JetExpression delegate = property.getDelegateExpression();
|
||||
if (delegate != null) {
|
||||
@@ -721,6 +750,10 @@ public class JetControlFlowProcessor {
|
||||
List<JetMultiDeclarationEntry> entries = declaration.getEntries();
|
||||
for (JetMultiDeclarationEntry entry : entries) {
|
||||
builder.declareVariable(entry);
|
||||
ResolvedCall<FunctionDescriptor> resolvedCall = trace.get(BindingContext.COMPONENT_RESOLVED_CALL, entry);
|
||||
if (resolvedCall != null) {
|
||||
builder.call(entry, resolvedCall);
|
||||
}
|
||||
builder.write(entry, entry);
|
||||
}
|
||||
}
|
||||
@@ -735,7 +768,6 @@ public class JetControlFlowProcessor {
|
||||
IElementType operationType = expression.getOperationReference().getReferencedNameElementType();
|
||||
if (operationType == JetTokens.COLON || operationType == JetTokens.AS_KEYWORD || operationType == JetTokens.AS_SAFE) {
|
||||
generateInstructions(expression.getLeft(), false);
|
||||
builder.read(expression);
|
||||
}
|
||||
else {
|
||||
visitJetElement(expression);
|
||||
@@ -753,20 +785,14 @@ public class JetControlFlowProcessor {
|
||||
|
||||
@Override
|
||||
public void visitArrayAccessExpression(@NotNull JetArrayAccessExpression expression) {
|
||||
for (JetExpression index : expression.getIndexExpressions()) {
|
||||
generateInstructions(index, false);
|
||||
if (!generateCall(expression)) {
|
||||
generateArrayAccess(expression);
|
||||
}
|
||||
generateInstructions(expression.getArrayExpression(), false);
|
||||
// TODO : read 'get' or 'set' function
|
||||
builder.read(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIsExpression(@NotNull JetIsExpression expression) {
|
||||
generateInstructions(expression.getLeftHandSide(), inCondition);
|
||||
// no CF for types
|
||||
// TODO : builder.read(expression.getPattern());
|
||||
builder.read(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -783,8 +809,6 @@ public class JetControlFlowProcessor {
|
||||
for (Iterator<JetWhenEntry> iterator = expression.getEntries().iterator(); iterator.hasNext(); ) {
|
||||
JetWhenEntry whenEntry = iterator.next();
|
||||
|
||||
builder.read(whenEntry);
|
||||
|
||||
boolean isElse = whenEntry.isElse();
|
||||
if (isElse) {
|
||||
hasElse = true;
|
||||
@@ -837,7 +861,7 @@ public class JetControlFlowProcessor {
|
||||
for (JetDeclaration function : functions) {
|
||||
generateInstructions(function, inCondition);
|
||||
}
|
||||
builder.read(expression);
|
||||
builder.createAnonymousObject(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -853,7 +877,7 @@ public class JetControlFlowProcessor {
|
||||
generateInstructions(entryWithExpression.getExpression(), false);
|
||||
}
|
||||
}
|
||||
builder.read(expression);
|
||||
builder.loadStringTemplate(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -913,5 +937,79 @@ public class JetControlFlowProcessor {
|
||||
public void visitJetElement(@NotNull JetElement element) {
|
||||
builder.unsupported(element);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ResolvedCall<?> getResolvedCall(@NotNull JetElement expression) {
|
||||
return trace.get(BindingContext.RESOLVED_CALL, expression);
|
||||
}
|
||||
|
||||
private boolean generateCall(JetExpression calleeExpression) {
|
||||
ResolvedCall<?> resolvedCall = getResolvedCall(calleeExpression);
|
||||
if (resolvedCall == null) {
|
||||
builder.compilationError(calleeExpression, "No resolved call");
|
||||
return false;
|
||||
}
|
||||
generateCall(calleeExpression, resolvedCall);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void generateCall(JetExpression calleeExpression, ResolvedCall<?> resolvedCall) {
|
||||
if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
|
||||
VariableAsFunctionResolvedCall variableAsFunctionResolvedCall = (VariableAsFunctionResolvedCall) resolvedCall;
|
||||
generateCall(calleeExpression, variableAsFunctionResolvedCall.getFunctionCall());
|
||||
return;
|
||||
}
|
||||
|
||||
CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor();
|
||||
if (resultingDescriptor instanceof ExpressionAsFunctionDescriptor) {
|
||||
generateInstructions(((ExpressionAsFunctionDescriptor) resultingDescriptor).getExpression(), false);
|
||||
}
|
||||
|
||||
generateReceiver(resolvedCall.getThisObject());
|
||||
generateReceiver(resolvedCall.getReceiverArgument());
|
||||
|
||||
for (ValueParameterDescriptor parameterDescriptor : resultingDescriptor.getValueParameters()) {
|
||||
ResolvedValueArgument argument = resolvedCall.getValueArguments().get(parameterDescriptor);
|
||||
if (argument == null) continue;
|
||||
|
||||
generateValueArgument(argument);
|
||||
}
|
||||
|
||||
if (resultingDescriptor instanceof VariableDescriptor) {
|
||||
builder.readVariable(calleeExpression, (VariableDescriptor) resultingDescriptor);
|
||||
}
|
||||
else {
|
||||
builder.call(calleeExpression, resolvedCall);
|
||||
}
|
||||
}
|
||||
|
||||
private void generateReceiver(ReceiverValue receiver) {
|
||||
if (!receiver.exists()) return;
|
||||
if (receiver instanceof ThisReceiver) {
|
||||
// TODO: Receiver is passed implicitly: no expression to tie the read to
|
||||
}
|
||||
else if (receiver instanceof ExpressionReceiver) {
|
||||
generateInstructions(((ExpressionReceiver) receiver).getExpression(), false);
|
||||
}
|
||||
else if (receiver instanceof TransientReceiver) {
|
||||
// Do nothing
|
||||
}
|
||||
else if (receiver instanceof AutoCastReceiver) {
|
||||
// No cast instruction in our CFG
|
||||
generateReceiver(((AutoCastReceiver) receiver).getOriginal());
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Unknown receiver kind: " + receiver);
|
||||
}
|
||||
}
|
||||
|
||||
private void generateValueArgument(ResolvedValueArgument argument) {
|
||||
for (ValueArgument valueArgument : argument.getArguments()) {
|
||||
JetExpression expression = valueArgument.getArgumentExpression();
|
||||
if (expression != null) {
|
||||
generateInstructions(expression, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+10
-2
@@ -80,11 +80,19 @@ public class InstructionVisitor {
|
||||
visitInstructionWithNext(instruction);
|
||||
}
|
||||
|
||||
public void visitWriteValue(WriteValueInstruction writeValueInstruction) {
|
||||
visitInstructionWithNext(writeValueInstruction);
|
||||
public void visitWriteValue(WriteValueInstruction instruction) {
|
||||
visitInstructionWithNext(instruction);
|
||||
}
|
||||
|
||||
public void visitLoadUnitValue(LoadUnitValueInstruction instruction) {
|
||||
visitInstructionWithNext(instruction);
|
||||
}
|
||||
|
||||
public void visitCallInstruction(CallInstruction instruction) {
|
||||
visitInstructionWithNext(instruction);
|
||||
}
|
||||
|
||||
public void visitCompilationErrorInstruction(CompilationErrorInstruction instruction) {
|
||||
visitInstructionWithNext(instruction);
|
||||
}
|
||||
}
|
||||
|
||||
+49
-6
@@ -20,7 +20,11 @@ import com.intellij.util.containers.Stack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.cfg.*;
|
||||
import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -251,11 +255,6 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
||||
add(new LocalFunctionDeclarationInstruction(subroutine, pseudocode));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(@NotNull JetElement element) {
|
||||
add(new ReadValueInstruction(element));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadUnit(@NotNull JetExpression expression) {
|
||||
add(new LoadUnitValueInstruction(expression));
|
||||
@@ -313,7 +312,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
||||
handleJumpInsideTryFinally(error);
|
||||
add(new ThrowExceptionInstruction(expression, error));
|
||||
}
|
||||
|
||||
|
||||
public void exitTryFinally() {
|
||||
BlockInfo pop = allBlocks.pop();
|
||||
assert pop instanceof TryFinallyBlockInfo;
|
||||
@@ -328,6 +327,50 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
||||
public void repeatPseudocode(@NotNull Label startLabel, @NotNull Label finishLabel) {
|
||||
pseudocode.repeatPart(startLabel, finishLabel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadConstant(@NotNull JetExpression expression, @Nullable CompileTimeConstant<?> constant) {
|
||||
read(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createAnonymousObject(@NotNull JetObjectLiteralExpression expression) {
|
||||
read(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadStringTemplate(@NotNull JetStringTemplateExpression expression) {
|
||||
read(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readThis(@NotNull JetExpression expression, @Nullable ReceiverParameterDescriptor parameterDescriptor) {
|
||||
read(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readVariable(@NotNull JetExpression expression, @Nullable VariableDescriptor variableDescriptor) {
|
||||
read(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void call(@NotNull JetExpression expression, @NotNull ResolvedCall<?> resolvedCall) {
|
||||
add(new CallInstruction(expression, resolvedCall));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void predefinedOperation(@NotNull JetExpression expression, @Nullable PredefinedOperation operation) {
|
||||
read(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compilationError(@NotNull JetElement element, @NotNull String message) {
|
||||
add(new CompilationErrorInstruction(element, message));
|
||||
}
|
||||
|
||||
private void read(@NotNull JetElement element) {
|
||||
add(new ReadValueInstruction(element));
|
||||
}
|
||||
}
|
||||
|
||||
public static class TryFinallyBlockInfo extends BlockInfo {
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2010-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.lang.cfg.pseudocode
|
||||
|
||||
import org.jetbrains.jet.lang.descriptors.VariableDescriptor
|
||||
import org.jetbrains.jet.lang.psi.JetElement
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall
|
||||
|
||||
class CallInstruction(
|
||||
element: JetElement,
|
||||
val resolvedCall: ResolvedCall<*>
|
||||
) : InstructionWithNext(element) {
|
||||
|
||||
override fun accept(visitor: InstructionVisitor) {
|
||||
visitor.visitCallInstruction(this)
|
||||
}
|
||||
|
||||
override fun createCopy() = CallInstruction(element, resolvedCall)
|
||||
|
||||
override fun toString() = "call(${element.getText()}, ${resolvedCall.getResultingDescriptor()!!.getName()})"
|
||||
}
|
||||
|
||||
class CompilationErrorInstruction(
|
||||
element: JetElement,
|
||||
val message: String
|
||||
) : InstructionWithNext(element) {
|
||||
|
||||
override fun accept(visitor: InstructionVisitor) {
|
||||
visitor.visitCompilationErrorInstruction(this)
|
||||
}
|
||||
|
||||
override fun createCopy() = CompilationErrorInstruction(element, message)
|
||||
|
||||
override fun toString() = "error(${element.getText()}, $message)"
|
||||
}
|
||||
Reference in New Issue
Block a user