diff --git a/idea/src/org/jetbrains/jet/JetNodeTypes.java b/idea/src/org/jetbrains/jet/JetNodeTypes.java index 6f489e41407..b94ef1c899a 100644 --- a/idea/src/org/jetbrains/jet/JetNodeTypes.java +++ b/idea/src/org/jetbrains/jet/JetNodeTypes.java @@ -94,6 +94,8 @@ public interface JetNodeTypes { JetNodeType OPERATION_REFERENCE = new JetNodeType("OPERATION_REFERENCE", JetSimpleNameExpression.class); JetNodeType LABEL_REFERENCE = new JetNodeType("LABEL_REFERENCE", JetSimpleNameExpression.class); + JetNodeType LABEL_QUALIFIER = new JetNodeType("LABEL_QUALIFIER", JetContainerNode.class); + JetNodeType THIS_EXPRESSION = new JetNodeType("THIS_EXPRESSION", JetThisExpression.class); JetNodeType BINARY_EXPRESSION = new JetNodeType("BINARY_EXPRESSION", JetBinaryExpression.class); JetNodeType BINARY_WITH_TYPE = new JetNodeType("BINARY_WITH_TYPE", JetBinaryExpressionWithTypeRHS.class); diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 9c2c2ebdae4..3a30a925c1c 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -196,7 +196,7 @@ public class ExpressionCodegen extends JetVisitor { public void visitConstantExpression(JetConstantExpression expression) { myStack.push(StackValue.constant(expression.getValue())); /* - Object value = expression.getValue(); + Object value = element.getValue(); v.aconst(value); if (value instanceof Integer) { diff --git a/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java b/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java index 181faebb6fa..17a4ccd154d 100644 --- a/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java +++ b/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java @@ -40,8 +40,8 @@ public interface JetControlFlowBuilder { void exitTryFinally(); // Subroutines - void enterSubroutine(@NotNull JetElement subroutine); - void exitSubroutine(@NotNull JetElement subroutine); + void enterSubroutine(@NotNull JetElement subroutine, boolean isFunctionLiteral); + void exitSubroutine(@NotNull JetElement subroutine, boolean functionLiteral); @Nullable JetElement getCurrentSubroutine(); diff --git a/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java b/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java new file mode 100644 index 00000000000..d6c163d71f8 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java @@ -0,0 +1,121 @@ +package org.jetbrains.jet.lang.cfg; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.psi.JetBlockExpression; +import org.jetbrains.jet.lang.psi.JetElement; +import org.jetbrains.jet.lang.psi.JetExpression; + +/** + * @author abreslav + */ +public class JetControlFlowBuilderAdapter implements JetControlFlowBuilder { + protected JetControlFlowBuilder builder; + + public JetControlFlowBuilderAdapter(JetControlFlowBuilder builder) { + this.builder = builder; + } + + @Override + public void readNode(@NotNull JetExpression expression) { + builder.readNode(expression); + } + + @Override + @NotNull + public Label createUnboundLabel() { + return builder.createUnboundLabel(); + } + + @Override + public void bindLabel(@NotNull Label label) { + builder.bindLabel(label); + } + + @Override + public void jump(@NotNull Label label) { + builder.jump(label); + } + + @Override + public void jumpOnFalse(@NotNull Label label) { + builder.jumpOnFalse(label); + } + + @Override + public void jumpOnTrue(@NotNull Label label) { + builder.jumpOnTrue(label); + } + + @Override + public void nondeterministicJump(Label label) { + builder.nondeterministicJump(label); + } + + @Override + public Label getEntryPoint(@NotNull JetElement labelElement) { + return builder.getEntryPoint(labelElement); + } + + @Override + public Label getExitPoint(@NotNull JetElement labelElement) { + return builder.getExitPoint(labelElement); + } + + @Override + public Label enterLoop(@NotNull JetExpression expression, Label loopExitPoint) { + return builder.enterLoop(expression, loopExitPoint); + } + + @Override + public void exitLoop(@NotNull JetExpression expression) { + builder.exitLoop(expression); + } + + @Override + @Nullable + public JetElement getCurrentLoop() { + return builder.getCurrentLoop(); + } + + @Override + public void enterTryFinally(@NotNull JetBlockExpression expression) { + builder.enterTryFinally(expression); + } + + @Override + public void exitTryFinally() { + builder.exitTryFinally(); + } + + @Override + public void enterSubroutine(@NotNull JetElement subroutine, boolean isFunctionLiteral) { + builder.enterSubroutine(subroutine, isFunctionLiteral); + } + + @Override + public void exitSubroutine(@NotNull JetElement subroutine, boolean functionLiteral) { + builder.exitSubroutine(subroutine, functionLiteral); + } + + @Override + @Nullable + public JetElement getCurrentSubroutine() { + return builder.getCurrentSubroutine(); + } + + @Override + public void returnValue(@NotNull JetElement subroutine) { + builder.returnValue(subroutine); + } + + @Override + public void returnNoValue(@NotNull JetElement subroutine) { + builder.returnNoValue(subroutine); + } + + @Override + public void unsupported(JetElement element) { + builder.unsupported(element); + } +} diff --git a/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowGraphBuilder.java b/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowGraphBuilder.java index 3f0a020c497..57dd42e1fbc 100644 --- a/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowGraphBuilder.java +++ b/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowGraphBuilder.java @@ -155,8 +155,8 @@ package org.jetbrains.jet.lang.cfg; // } // // @Override -// public void readNode(JetExpression expression) { -// createNode(expression); +// public void readNode(JetExpression element) { +// createNode(element); // } // // @Override @@ -236,7 +236,7 @@ package org.jetbrains.jet.lang.cfg; // } // // @Override -// public void enterTryFinally(JetBlockExpression expression) { +// public void enterTryFinally(JetBlockExpression element) { // throw new UnsupportedOperationException(); // TODO // } // diff --git a/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index 68b3e01aede..d1dc349fd03 100644 --- a/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/idea/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -1,10 +1,11 @@ package org.jetbrains.jet.lang.cfg; -import com.intellij.lang.ASTNode; import com.intellij.psi.tree.IElementType; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.JetSemanticServices; import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.types.BindingTrace; import org.jetbrains.jet.lexer.JetTokens; import java.util.*; @@ -18,10 +19,12 @@ public class JetControlFlowProcessor { private final JetSemanticServices semanticServices; private final JetControlFlowBuilder builder; + private final BindingTrace trace; - public JetControlFlowProcessor(JetSemanticServices semanticServices, JetControlFlowBuilder builder) { + public JetControlFlowProcessor(JetSemanticServices semanticServices, BindingTrace trace, JetControlFlowBuilder builder) { this.semanticServices = semanticServices; this.builder = builder; + this.trace = trace; } public void generate(@NotNull JetElement subroutineElement, @NotNull JetExpression body) { @@ -29,11 +32,16 @@ public class JetControlFlowProcessor { } public void generateSubroutineControlFlow(@NotNull JetElement subroutineElement, @NotNull List body, boolean preferBlocks) { - builder.enterSubroutine(subroutineElement); + if (subroutineElement instanceof JetNamedDeclaration) { + JetNamedDeclaration namedDeclaration = (JetNamedDeclaration) subroutineElement; + enterLabeledElement(namedDeclaration.getName(), namedDeclaration); + } + boolean functionLiteral = subroutineElement instanceof JetFunctionLiteralExpression; + builder.enterSubroutine(subroutineElement, functionLiteral); for (JetElement statement : body) { statement.accept(new CFPVisitor(preferBlocks)); } - builder.exitSubroutine(subroutineElement); + builder.exitSubroutine(subroutineElement, functionLiteral); } private void enterLabeledElement(@NotNull String labelName, @NotNull JetElement labeledElement) { @@ -46,16 +54,36 @@ public class JetControlFlowProcessor { } private void exitElement(JetElement element) { -// for (Iterator> iterator = labeledElements.entrySet().iterator(); iterator.hasNext(); ) { -// Map.Entry entry = iterator.next(); -// if (entry.getValue() == element) { -// iterator.remove(); -// } -// } + // TODO : really suboptimal + for (Iterator>> mapIter = labeledElements.entrySet().iterator(); mapIter.hasNext(); ) { + Map.Entry> entry = mapIter.next(); + Stack stack = entry.getValue(); + for (Iterator stackIter = stack.iterator(); stackIter.hasNext(); ) { + JetElement recorded = stackIter.next(); + if (recorded == element) { + stackIter.remove(); + } + } + if (stack.isEmpty()) { + mapIter.remove(); + } + } } - private JetElement resolveLabel(@NotNull String labelName, @NotNull ASTNode labelNode) { - throw new UnsupportedOperationException(); // TODO + @Nullable + private JetElement resolveLabel(@NotNull String labelName, @NotNull JetSimpleNameExpression labelExpression) { + Stack stack = labeledElements.get(labelName); + if (stack == null || stack.isEmpty()) { + semanticServices.getErrorHandler().unresolvedReference(labelExpression); + return null; + } + else if (stack.size() > 1) { + semanticServices.getErrorHandler().genericWarning(labelExpression.getNode(), "There is more than one label with such a name in this scope"); + } + + JetElement result = stack.peek(); + trace.recordLabelResolution(labelExpression, result); + return result; } private class CFPVisitor extends JetVisitor { @@ -74,6 +102,7 @@ public class JetControlFlowProcessor { visitor = new CFPVisitor(preferBlock); } element.accept(visitor); + exitElement(element); } @Override @@ -88,8 +117,14 @@ public class JetControlFlowProcessor { @Override public void visitLabelQualifiedExpression(JetLabelQualifiedExpression expression) { - enterLabeledElement(expression.getLabelName(), expression.getLabeledExpression()); - value(expression.getLabeledExpression(), false); + String labelName = expression.getLabelName(); + JetExpression labeledExpression = expression.getLabeledExpression(); + visitLabeledExpression(labelName, labeledExpression); + } + + private void visitLabeledExpression(@NotNull String labelName, @NotNull JetExpression labeledExpression) { + enterLabeledElement(labelName, labeledExpression); + value(labeledExpression, false); } @Override @@ -121,6 +156,17 @@ public class JetControlFlowProcessor { } } + @Override + public void visitUnaryExpression(JetUnaryExpression expression) { + IElementType operationType = expression.getOperationSign().getReferencedNameElementType(); + if (JetTokens.LABELS.contains(operationType)) { + visitLabeledExpression(expression.getOperationSign().getReferencedName().substring(1), expression.getBaseExpression()); + } + else { + visitElement(expression); + } + } + @Override public void visitIfExpression(JetIfExpression expression) { value(expression.getCondition(), false); @@ -135,7 +181,7 @@ public class JetControlFlowProcessor { value(elseBranch, true); } builder.bindLabel(resultLabel); - // builder.readNode(expression); + // builder.readNode(element); } @Override @@ -210,7 +256,7 @@ public class JetControlFlowProcessor { public void visitBreakExpression(JetBreakExpression expression) { JetSimpleNameExpression labelElement = expression.getTargetLabel(); Label exitPoint = (labelElement != null) - ? builder.getExitPoint(labelElement) + ? builder.getExitPoint(resolveLabel(expression.getLabelName(), expression.getTargetLabel())) : builder.getExitPoint(builder.getCurrentLoop()); builder.jump(exitPoint); } @@ -219,7 +265,7 @@ public class JetControlFlowProcessor { public void visitContinueExpression(JetContinueExpression expression) { JetSimpleNameExpression labelElement = expression.getTargetLabel(); if (labelElement != null) { - builder.jump(builder.getEntryPoint(labelElement)); + builder.jump(builder.getEntryPoint(resolveLabel(expression.getLabelName(), expression.getTargetLabel()))); } else { builder.jump(builder.getEntryPoint(builder.getCurrentLoop())); @@ -234,7 +280,7 @@ public class JetControlFlowProcessor { } JetSimpleNameExpression labelElement = expression.getTargetLabel(); JetElement subroutine = (labelElement != null) - ? resolveLabel(expression.getLabelName(), expression.getTargetLabel().getNode()) + ? resolveLabel(expression.getLabelName(), expression.getTargetLabel()) : builder.getCurrentSubroutine(); if (returnedExpression == null) { builder.returnNoValue(subroutine); diff --git a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/ExpressionInstruction.java b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/ExpressionInstruction.java deleted file mode 100644 index 1f99f0f8e36..00000000000 --- a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/ExpressionInstruction.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.jetbrains.jet.lang.cfg.pseudocode; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.psi.JetExpression; - -/** - * @author abreslav - */ -public abstract class ExpressionInstruction extends Instruction { - protected final JetExpression expression; - - public ExpressionInstruction(@NotNull JetExpression expression) { - this.expression = expression; - } - - @NotNull - public JetExpression getExpression() { - return expression; - } -} diff --git a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/FunctionLiteralValueInstruction.java b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/FunctionLiteralValueInstruction.java new file mode 100644 index 00000000000..6b7d7b804fd --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/FunctionLiteralValueInstruction.java @@ -0,0 +1,34 @@ +package org.jetbrains.jet.lang.cfg.pseudocode; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.psi.JetElement; + +/** +* @author abreslav +*/ +public class FunctionLiteralValueInstruction extends InstructionWithNext { + + private Pseudocode body; + + public FunctionLiteralValueInstruction(@NotNull JetElement element) { + super(element); + } + + public Pseudocode getBody() { + return body; + } + + public void setBody(Pseudocode body) { + this.body = body; + } + + @Override + public void accept(InstructionVisitor visitor) { + visitor.visitFunctionLiteralValue(this); + } + + @Override + public String toString() { + return "rf(" + element.getText() + ")"; + } +} diff --git a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/InstructionVisitor.java b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/InstructionVisitor.java index aa780306eea..1841e9ee723 100644 --- a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/InstructionVisitor.java +++ b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/InstructionVisitor.java @@ -4,8 +4,12 @@ package org.jetbrains.jet.lang.cfg.pseudocode; * @author abreslav */ public class InstructionVisitor { - public void visitRead(ValueInstruction instruction) { - visitInstruction(instruction); + public void visitReadValue(ReadValueInstruction instruction) { + visitInstructionWithNext(instruction); + } + + public void visitFunctionLiteralValue(FunctionLiteralValueInstruction instruction) { + visitInstructionWithNext(instruction); } public void visitUnconditionalJump(UnconditionalJumpInstruction instruction) { @@ -24,6 +28,14 @@ public class InstructionVisitor { visitJump(instruction); } + public void visitNondeterministicJump(NondeterministicJumpInstruction instruction) { + visitJump(instruction); + } + + public void visitUnsupportedElementInstruction(UnsupportedElementInstruction instruction) { + visitInstructionWithNext(instruction); + } + public void visitSubroutineExit(SubroutineExitInstruction instruction) { visitInstruction(instruction); } @@ -32,10 +44,10 @@ public class InstructionVisitor { visitInstruction(instruction); } - public void visitInstruction(Instruction instruction) { + public void visitInstructionWithNext(InstructionWithNext instruction) { + visitInstruction(instruction); } - public void visitNondeterministicJump(NondeterministicJumpInstruction instruction) { - visitJump(instruction); + public void visitInstruction(Instruction instruction) { } } diff --git a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/InstructionWithNext.java b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/InstructionWithNext.java index 0c273dafb13..d7c7b16c1a8 100644 --- a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/InstructionWithNext.java +++ b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/InstructionWithNext.java @@ -1,15 +1,16 @@ package org.jetbrains.jet.lang.cfg.pseudocode; -import org.jetbrains.jet.lang.psi.JetExpression; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.psi.JetElement; /** * @author abreslav */ -public abstract class InstructionWithNext extends ExpressionInstruction { +public abstract class InstructionWithNext extends JetElementInstruction { private Instruction next; - public InstructionWithNext(JetExpression expression) { - super(expression); + protected InstructionWithNext(@NotNull JetElement element) { + super(element); } public Instruction getNext() { diff --git a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java index 8c3d0e11094..0cfe7f36960 100644 --- a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java +++ b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java @@ -1,7 +1,9 @@ package org.jetbrains.jet.lang.cfg.pseudocode; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.cfg.JetControlFlowBuilder; +import org.jetbrains.jet.lang.cfg.JetControlFlowBuilderAdapter; import org.jetbrains.jet.lang.cfg.Label; import org.jetbrains.jet.lang.psi.JetBlockExpression; import org.jetbrains.jet.lang.psi.JetElement; @@ -14,7 +16,55 @@ import java.util.Stack; /** * @author abreslav */ -public class JetControlFlowInstructionsGenerator implements JetControlFlowBuilder { +public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAdapter { + + private int labelCount = 0; + private final Stack builders = new Stack(); + + public JetControlFlowInstructionsGenerator() { + super(null); + pushBuilder(); + } + + private void pushBuilder() { + Pseudocode parentPseudocode = builder == null ? new Pseudocode(null) : builders.peek().getPseudocode(); + JetControlFlowInstructionsGeneratorWorker worker = new JetControlFlowInstructionsGeneratorWorker(parentPseudocode); + builders.push(worker); + builder = worker; + } + + private JetControlFlowInstructionsGeneratorWorker popBuilder() { + JetControlFlowInstructionsGeneratorWorker worker = builders.pop(); + builder = builders.peek(); + return worker; + } + + @Override + public void enterSubroutine(@NotNull JetElement subroutine, boolean isFunctionLiteral) { + if (isFunctionLiteral) { + pushBuilder(); + builder.enterSubroutine(subroutine, false); + } + else { + super.enterSubroutine(subroutine, isFunctionLiteral); + } + } + + @Override + public void exitSubroutine(@NotNull JetElement subroutine, boolean functionLiteral) { + super.exitSubroutine(subroutine, functionLiteral); + if (functionLiteral) { + JetControlFlowInstructionsGeneratorWorker worker = popBuilder(); + JetControlFlowInstructionsGeneratorWorker builder = builders.peek(); + FunctionLiteralValueInstruction instruction = new FunctionLiteralValueInstruction(subroutine); + builder.add(instruction); + instruction.setBody(worker.getPseudocode()); + } + } + + public Pseudocode getPseudocode() { + return builders.peek().getPseudocode(); + } private static class BlockInfo { private final JetElement element; @@ -40,137 +90,141 @@ public class JetControlFlowInstructionsGenerator implements JetControlFlowBuilde } } - private final Stack loopInfo = new Stack(); - private final Stack subroutineInfo = new Stack(); - private final Map elementToBlockInfo = new HashMap(); + private class JetControlFlowInstructionsGeneratorWorker implements JetControlFlowBuilder { + private final Stack loopInfo = new Stack(); + private final Stack subroutineInfo = new Stack(); - private int labelCount = 0; + private final Map elementToBlockInfo = new HashMap(); - private final Pseudocode pseudocode = new Pseudocode(); + private final Pseudocode pseudocode; - public Pseudocode getPseudocode() { - return pseudocode; - } + private JetControlFlowInstructionsGeneratorWorker(@Nullable Pseudocode parent) { + this.pseudocode = new Pseudocode(parent); + } - private void add(Instruction instruction) { - pseudocode.getInstructions().add(instruction); - } + public Pseudocode getPseudocode() { + return pseudocode; + } - @NotNull - @Override - public final Label createUnboundLabel() { - return new Label("l" + labelCount++); - } + private void add(Instruction instruction) { + pseudocode.addInstruction(instruction); + } - @Override - public final Label enterLoop(@NotNull JetExpression expression, Label loopExitPoint) { - Label label = createUnboundLabel(); - bindLabel(label); - BlockInfo blockInfo = new BlockInfo(expression, label, loopExitPoint); - loopInfo.push(blockInfo); - elementToBlockInfo.put(expression, blockInfo); - return label; - } + @NotNull + @Override + public final Label createUnboundLabel() { + return new Label("l" + labelCount++); + } - @Override - public final void exitLoop(@NotNull JetExpression expression) { - BlockInfo info = loopInfo.pop(); - elementToBlockInfo.remove(expression); - bindLabel(info.getExitPoint()); - } + @Override + public final Label enterLoop(@NotNull JetExpression expression, Label loopExitPoint) { + Label label = createUnboundLabel(); + bindLabel(label); + BlockInfo blockInfo = new BlockInfo(expression, label, loopExitPoint); + loopInfo.push(blockInfo); + elementToBlockInfo.put(expression, blockInfo); + return label; + } - @Override - public JetElement getCurrentLoop() { - return loopInfo.empty() ? null : loopInfo.peek().getElement(); - } + @Override + public final void exitLoop(@NotNull JetExpression expression) { + BlockInfo info = loopInfo.pop(); + elementToBlockInfo.remove(expression); + bindLabel(info.getExitPoint()); + } - @Override - public void enterSubroutine(@NotNull JetElement subroutine) { - Label entryPoint = createUnboundLabel(); - BlockInfo blockInfo = new BlockInfo(subroutine, entryPoint, createUnboundLabel()); - subroutineInfo.push(blockInfo); - elementToBlockInfo.put(subroutine, blockInfo); - bindLabel(entryPoint); - } + @Override + public JetElement getCurrentLoop() { + return loopInfo.empty() ? null : loopInfo.peek().getElement(); + } - @Override - public JetElement getCurrentSubroutine() { - return subroutineInfo.empty() ? null : subroutineInfo.peek().getElement(); - } + @Override + public void enterSubroutine(@NotNull JetElement subroutine, boolean isFunctionLiteral) { + Label entryPoint = createUnboundLabel(); + BlockInfo blockInfo = new BlockInfo(subroutine, entryPoint, createUnboundLabel()); + subroutineInfo.push(blockInfo); + elementToBlockInfo.put(subroutine, blockInfo); + bindLabel(entryPoint); + } - @Override - public Label getEntryPoint(@NotNull JetElement labelElement) { - return elementToBlockInfo.get(labelElement).getEntryPoint(); - } + @Override + public JetElement getCurrentSubroutine() { + return subroutineInfo.empty() ? null : subroutineInfo.peek().getElement(); + } - @Override - public Label getExitPoint(@NotNull JetElement labelElement) { - return elementToBlockInfo.get(labelElement).getExitPoint(); - } + @Override + public Label getEntryPoint(@NotNull JetElement labelElement) { + return elementToBlockInfo.get(labelElement).getEntryPoint(); + } + + @Override + public Label getExitPoint(@NotNull JetElement labelElement) { + return elementToBlockInfo.get(labelElement).getExitPoint(); + } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - @Override - public void exitSubroutine(@NotNull JetElement subroutine) { - bindLabel(getExitPoint(subroutine)); - add(new SubroutineExitInstruction(subroutine)); - elementToBlockInfo.remove(subroutine); - } + @Override + public void exitSubroutine(@NotNull JetElement subroutine, boolean functionLiteral) { + bindLabel(getExitPoint(subroutine)); + add(new SubroutineExitInstruction(subroutine)); + elementToBlockInfo.remove(subroutine); + } - @Override - public void returnValue(@NotNull JetElement subroutine) { - add(new ReturnValueInstruction(getExitPoint(subroutine))); - } + @Override + public void returnValue(@NotNull JetElement subroutine) { + add(new ReturnValueInstruction(getExitPoint(subroutine))); + } - @Override - public void returnNoValue(@NotNull JetElement subroutine) { - add(new ReturnNoValueInstruction(getExitPoint(subroutine))); - } + @Override + public void returnNoValue(@NotNull JetElement subroutine) { + add(new ReturnNoValueInstruction(getExitPoint(subroutine))); + } - @Override - public void readNode(@NotNull JetExpression expression) { - add(new ValueInstruction(expression)); - } + @Override + public void readNode(@NotNull JetExpression expression) { + add(new ReadValueInstruction(expression)); + } - @Override - public void jump(@NotNull Label label) { - add(new UnconditionalJumpInstruction(label)); - } + @Override + public void jump(@NotNull Label label) { + add(new UnconditionalJumpInstruction(label)); + } - @Override - public void jumpOnFalse(@NotNull Label label) { - add(new ConditionalJumpInstruction(false, label)); - } + @Override + public void jumpOnFalse(@NotNull Label label) { + add(new ConditionalJumpInstruction(false, label)); + } - @Override - public void jumpOnTrue(@NotNull Label label) { - add(new ConditionalJumpInstruction(true, label)); - } + @Override + public void jumpOnTrue(@NotNull Label label) { + add(new ConditionalJumpInstruction(true, label)); + } - @Override - public void bindLabel(@NotNull Label label) { - pseudocode.getLabels().put(label, pseudocode.getInstructions().size()); - } + @Override + public void bindLabel(@NotNull Label label) { + pseudocode.addLabel(label); + } - @Override - public void nondeterministicJump(Label label) { - add(new NondeterministicJumpInstruction(label)); - } + @Override + public void nondeterministicJump(Label label) { + add(new NondeterministicJumpInstruction(label)); + } - @Override - public void enterTryFinally(@NotNull JetBlockExpression expression) { - throw new UnsupportedOperationException(); // TODO - } + @Override + public void enterTryFinally(@NotNull JetBlockExpression expression) { + throw new UnsupportedOperationException(); // TODO + } - @Override - public void exitTryFinally() { - throw new UnsupportedOperationException(); // TODO - } + @Override + public void exitTryFinally() { + throw new UnsupportedOperationException(); // TODO + } - @Override - public void unsupported(JetElement element) { - throw new IllegalStateException("Unsupported element: " + element.getText() + " " + element); + @Override + public void unsupported(JetElement element) { + add(new UnsupportedElementInstruction(element)); + } } - } diff --git a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetElementInstruction.java b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetElementInstruction.java new file mode 100644 index 00000000000..c99d41a8d7c --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/JetElementInstruction.java @@ -0,0 +1,20 @@ +package org.jetbrains.jet.lang.cfg.pseudocode; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.psi.JetElement; + +/** + * @author abreslav + */ +public abstract class JetElementInstruction extends Instruction { + protected final JetElement element; + + public JetElementInstruction(@NotNull JetElement element) { + this.element = element; + } + + @NotNull + public JetElement getElement() { + return element; + } +} diff --git a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java index 1e823439823..d08d38f8c77 100644 --- a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java +++ b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/Pseudocode.java @@ -1,6 +1,7 @@ package org.jetbrains.jet.lang.cfg.pseudocode; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.cfg.Label; import java.io.PrintStream; @@ -13,12 +14,28 @@ public class Pseudocode { private final List instructions = new ArrayList(); private final Map labels = new LinkedHashMap(); - public List getInstructions() { - return instructions; + @Nullable + private final Pseudocode parent; + + public Pseudocode(Pseudocode parent) { + this.parent = parent; } - public Map getLabels() { - return labels; + public void addInstruction(Instruction instruction) { + instructions.add(instruction); + } + + public void addLabel(Label label) { + labels.put(label, instructions.size()); + } + + @Nullable + private Integer resolveLabel(Label targetLabel) { + Integer result = labels.get(targetLabel); + if (result == null && parent != null) { + return parent.resolveLabel(targetLabel); + } + return result; } public void postProcess() { @@ -27,7 +44,7 @@ public class Pseudocode { final int currentPosition = i; instruction.accept(new InstructionVisitor() { @Override - public void visitRead(ValueInstruction instruction) { + public void visitInstructionWithNext(InstructionWithNext instruction) { instruction.setNext(getNextPosition(currentPosition)); } @@ -57,6 +74,12 @@ public class Pseudocode { visitJump(instruction); } + @Override + public void visitFunctionLiteralValue(FunctionLiteralValueInstruction instruction) { + instruction.getBody().postProcess(); + super.visitFunctionLiteralValue(instruction); + } + @Override public void visitSubroutineExit(SubroutineExitInstruction instruction) { // Nothing @@ -72,7 +95,7 @@ public class Pseudocode { @NotNull private Instruction getJumpTarget(@NotNull Label targetLabel) { - Integer targetPosition = labels.get(targetLabel); + Integer targetPosition = resolveLabel(targetLabel); return getTargetInstruction(targetPosition); } @@ -87,7 +110,7 @@ public class Pseudocode { } Label label = ((UnconditionalJumpInstruction) targetInstruction).getTargetLabel(); - targetPosition = labels.get(label); + targetPosition = resolveLabel(label); } } @@ -111,15 +134,19 @@ public class Pseudocode { } public void dumpGraph(@NotNull final PrintStream out) { - out.println("digraph g {"); + String graphHeader = "digraph g"; + dumpSubgraph(out, graphHeader, new int[1], ""); + } + + private void dumpSubgraph(final PrintStream out, String graphHeader, final int[] count, String style) { + out.println(graphHeader + " {"); final Map nodeToName = new HashMap(); - int count = 0; for (Instruction node : instructions) { if (node instanceof UnconditionalJumpInstruction) { continue; } - String name = "n" + count++; + String name = "n" + count[0]++; nodeToName.put(node, name); String text = node.toString(); int newline = text.indexOf("\n"); @@ -133,11 +160,25 @@ public class Pseudocode { else if (node instanceof NondeterministicJumpInstruction) { shape = "Mdiamond"; } + else if (node instanceof UnsupportedElementInstruction) { + shape = "box, fillcolor=red, style=filled"; + } + else if (node instanceof FunctionLiteralValueInstruction) { + shape = "Mcircle"; + } out.println(name + "[label=\"" + text + "\", shape=" + shape + "];"); } for (final Instruction fromInst : instructions) { fromInst.accept(new InstructionVisitor() { + @Override + public void visitFunctionLiteralValue(FunctionLiteralValueInstruction instruction) { + int index = count[0]; + instruction.getBody().dumpSubgraph(out, "subgraph f" + index, count, "color=blue;\ntlabel = \"process #" + index + "\";"); + printEdge(out, nodeToName.get(instruction), "n" + index, null); + visitInstructionWithNext(instruction); + } + @Override public void visitUnconditionalJump(UnconditionalJumpInstruction instruction) { // Nothing @@ -145,13 +186,13 @@ public class Pseudocode { @Override public void visitJump(AbstractJumpInstruction instruction) { - writeEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getResolvedTarget()), null); + printEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getResolvedTarget()), null); } @Override public void visitNondeterministicJump(NondeterministicJumpInstruction instruction) { visitJump(instruction); - writeEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getNext()), null); + printEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getNext()), null); } @Override @@ -167,13 +208,13 @@ public class Pseudocode { @Override public void visitConditionalJump(ConditionalJumpInstruction instruction) { String from = nodeToName.get(instruction); - writeEdge(out, from, nodeToName.get(instruction.getNextOnFalse()), "no"); - writeEdge(out, from, nodeToName.get(instruction.getNextOnTrue()), "yes"); + printEdge(out, from, nodeToName.get(instruction.getNextOnFalse()), "no"); + printEdge(out, from, nodeToName.get(instruction.getNextOnTrue()), "yes"); } @Override - public void visitRead(ValueInstruction instruction) { - writeEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getNext()), null); + public void visitInstructionWithNext(InstructionWithNext instruction) { + printEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getNext()), null); } @Override @@ -187,11 +228,11 @@ public class Pseudocode { } }); } + out.println(style); out.println("}"); - out.close(); } - private void writeEdge(PrintStream out, String from, String to, String label) { + private void printEdge(PrintStream out, String from, String to, String label) { if (label != null) { label = "[label=\"" + label + "\"]"; } diff --git a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/ValueInstruction.java b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/ReadValueInstruction.java similarity index 60% rename from idea/src/org/jetbrains/jet/lang/cfg/pseudocode/ValueInstruction.java rename to idea/src/org/jetbrains/jet/lang/cfg/pseudocode/ReadValueInstruction.java index ca0e53e6fc5..b8847d46211 100644 --- a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/ValueInstruction.java +++ b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/ReadValueInstruction.java @@ -6,19 +6,19 @@ import org.jetbrains.jet.lang.psi.JetExpression; /** * @author abreslav */ -public class ValueInstruction extends InstructionWithNext { +public class ReadValueInstruction extends InstructionWithNext { - public ValueInstruction(@NotNull JetExpression expression) { + public ReadValueInstruction(@NotNull JetExpression expression) { super(expression); } @Override public void accept(InstructionVisitor visitor) { - visitor.visitRead(this); + visitor.visitReadValue(this); } @Override public String toString() { - return "r(" + expression.getText() + ")"; + return "r(" + element.getText() + ")"; } } diff --git a/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/UnsupportedElementInstruction.java b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/UnsupportedElementInstruction.java new file mode 100644 index 00000000000..fbe382589b4 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/cfg/pseudocode/UnsupportedElementInstruction.java @@ -0,0 +1,24 @@ +package org.jetbrains.jet.lang.cfg.pseudocode; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.psi.JetElement; + +/** + * @author abreslav + */ +public class UnsupportedElementInstruction extends InstructionWithNext { + + protected UnsupportedElementInstruction(@NotNull JetElement element) { + super(element); + } + + @Override + public void accept(InstructionVisitor visitor) { + visitor.visitUnsupportedElementInstruction(this); + } + + @Override + public String toString() { + return "unsupported(" + element + " : " + element.getText() + ")"; + } +} diff --git a/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java b/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java index adc6e3f2579..a00cc44bb9a 100644 --- a/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java +++ b/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java @@ -227,9 +227,9 @@ public class JetExpressionParsing extends AbstractJetParsing { } /* - * expression - * : attributes expression - * : "(" expression ")" // see tupleLiteral + * element + * : attributes element + * : "(" element ")" // see tupleLiteral * : literalConstant * : functionLiteral * : tupleLiteral @@ -238,7 +238,7 @@ public class JetExpressionParsing extends AbstractJetParsing { * : expressionWithPrecedences * : if * : try - * : "typeof" "(" expression ")" + * : "typeof" "(" element ")" * : "new" constructorInvocation * : objectLiteral * : declaration @@ -249,14 +249,14 @@ public class JetExpressionParsing extends AbstractJetParsing { */ public void parseExpression() { if (!atSet(EXPRESSION_FIRST)) { - error("Expecting an expression"); + error("Expecting an element"); return; } parseBinaryExpression(Precedence.ASSIGNMENT); } /* - * expression (operation expression)* + * element (operation element)* * * see the precedence table */ @@ -427,7 +427,7 @@ public class JetExpressionParsing extends AbstractJetParsing { } /* - * expression (getEntryPoint? functionLiteral)? + * element (getEntryPoint? functionLiteral)? */ protected boolean parseCallWithClosure() { boolean success = false; @@ -447,9 +447,9 @@ public class JetExpressionParsing extends AbstractJetParsing { /* * atomicExpression - * : tupleLiteral // or parenthesized expression + * : tupleLiteral // or parenthesized element * : "this" getEntryPoint? ("<" type ">")? - * : "typeof" "(" expression ")" + * : "typeof" "(" element ")" * : "new" constructorInvocation * : objectLiteral * : jump @@ -535,8 +535,8 @@ public class JetExpressionParsing extends AbstractJetParsing { parseFunctionLiteral(); } else if (!parseLiteralConstant()) { - // TODO: better recovery if FIRST(expression) did not match - errorWithRecovery("Expecting an expression", EXPRESSION_FOLLOW); + // TODO: better recovery if FIRST(element) did not match + errorWithRecovery("Expecting an element", EXPRESSION_FOLLOW); } } @@ -581,7 +581,7 @@ public class JetExpressionParsing extends AbstractJetParsing { /* * when - * : "when" "(" (modifiers "val" SimpleName "=")? expression ")" "{" + * : "when" "(" (modifiers "val" SimpleName "=")? element ")" "{" * whenEntry* * "}" * ; @@ -622,8 +622,8 @@ public class JetExpressionParsing extends AbstractJetParsing { /* * whenEntry * // TODO : consider empty after => - * : whenConditionIf{","} (when | "=>" expression SEMI) - * : "else" ("continue" | "=>" expression SEMI) + * : whenConditionIf{","} (when | "=>" element SEMI) + * : "else" ("continue" | "=>" element SEMI) * ; */ private void parseWhenEntry() { @@ -633,7 +633,7 @@ public class JetExpressionParsing extends AbstractJetParsing { advance(); // ELSE_KEYWORD if (!at(CONTINUE_KEYWORD) && !at(DOUBLE_ARROW)) { - errorUntil("Expecting 'continue' or '=> expression'", TokenSet.create(CONTINUE_KEYWORD, DOUBLE_ARROW, + errorUntil("Expecting 'continue' or '=> element'", TokenSet.create(CONTINUE_KEYWORD, DOUBLE_ARROW, RBRACE, EOL_OR_SEMICOLON)); } @@ -641,14 +641,14 @@ public class JetExpressionParsing extends AbstractJetParsing { advance(); // DOUBLE_ARROW if (atSet(WHEN_CONDITION_RECOVERY_SET)) { - error("Expecting an expression"); + error("Expecting an element"); } else { parseExpression(); } } else if (at(CONTINUE_KEYWORD)) { advance(); // CONTINUE_KEYWORD } else if (!atSet(WHEN_CONDITION_RECOVERY_SET)) { - errorAndAdvance("Expecting 'continue' or '=> expression'"); + errorAndAdvance("Expecting 'continue' or '=> element'"); } } else { parseWhenEntryNotElse(); @@ -659,7 +659,7 @@ public class JetExpressionParsing extends AbstractJetParsing { } /* - * : whenConditionIf{","} (when | "=>" expression SEMI) + * : whenConditionIf{","} (when | "=>" element SEMI) */ private void parseWhenEntryNotElse() { while (true) { @@ -673,7 +673,7 @@ public class JetExpressionParsing extends AbstractJetParsing { } else { expect(DOUBLE_ARROW, "Expecting '=>' or 'when'", WHEN_CONDITION_RECOVERY_SET); if (atSet(WHEN_CONDITION_RECOVERY_SET)) { - error("Expecting an expression"); + error("Expecting an element"); } else { parseExpression(); } @@ -683,7 +683,7 @@ public class JetExpressionParsing extends AbstractJetParsing { /* * whenConditionIf - * : pattern ("if" "(" expression ")")? + * : pattern ("if" "(" element ")")? * ; */ private void parseWhenConditionIf() { @@ -705,9 +705,9 @@ public class JetExpressionParsing extends AbstractJetParsing { /* * whenCondition - * : expression + * : element * : "." postfixExpression typeArguments? valueArguments? - * : ("in" | "!in") expression + * : ("in" | "!in") element * : ("is" | "!is") isRHS * ; */ @@ -718,7 +718,7 @@ public class JetExpressionParsing extends AbstractJetParsing { advance(); // IN_KEYWORD or NOT_IN if (atSet(WHEN_CONDITION_RECOVERY_SET_WITH_DOUBLE_ARROW)) { - error("Expecting an expression"); + error("Expecting an element"); } else { parseExpression(); } @@ -739,7 +739,7 @@ public class JetExpressionParsing extends AbstractJetParsing { } } else { if (atSet(WHEN_CONDITION_RECOVERY_SET_WITH_DOUBLE_ARROW)) { - error("Expecting an expression, is-condition or in-condition"); + error("Expecting an element, is-condition or in-condition"); } else { parseExpression(); } @@ -782,7 +782,7 @@ public class JetExpressionParsing extends AbstractJetParsing { myJetParsing.parseTypeRef(); if (at(AT)) { - errorAndAdvance("'@' is allowed only after a decomposer expression, not after a type"); + errorAndAdvance("'@' is allowed only after a decomposer element, not after a type"); } if (myBuilder.getCurrentOffset() < expressionEndOffset) { rollbackMarker.rollbackTo(); @@ -853,8 +853,8 @@ public class JetExpressionParsing extends AbstractJetParsing { * binding * : "is" pattern * : "!is" pattern - * : "in" expression - * : "!in" expression + * : "in" element + * : "!in" element * : ":" type * ; */ @@ -882,7 +882,7 @@ public class JetExpressionParsing extends AbstractJetParsing { /* * arrayAccess - * : "[" expression{","} "]" + * : "[" element{","} "]" * ; */ private void parseArrayAccess() { @@ -894,9 +894,9 @@ public class JetExpressionParsing extends AbstractJetParsing { advance(); // LBRACKET while (true) { - if (at(COMMA)) errorAndAdvance("Expecting an index expression"); + if (at(COMMA)) errorAndAdvance("Expecting an index element"); if (at(RBRACKET)) { - error("Expecting an index expression"); + error("Expecting an index element"); break; } parseExpression(); @@ -1073,13 +1073,13 @@ public class JetExpressionParsing extends AbstractJetParsing { /* * expressions - * : SEMI* expression{SEMI+} SEMI* + * : SEMI* element{SEMI+} SEMI* */ public void parseExpressions() { while (at(SEMICOLON)) advance(); // SEMICOLON while (!eof() && !at(RBRACE)) { if (!atSet(EXPRESSION_FIRST)) { - errorAndAdvance("Expecting an expression"); + errorAndAdvance("Expecting an element"); } if (atSet(EXPRESSION_FIRST)) { parseExpression(); @@ -1126,7 +1126,7 @@ public class JetExpressionParsing extends AbstractJetParsing { /* * doWhile - * : "do" expression "while" "(" expression ")" + * : "do" element "while" "(" element ")" * ; */ private void parseDoWhile() { @@ -1149,7 +1149,7 @@ public class JetExpressionParsing extends AbstractJetParsing { /* * while - * : "while" "(" expression ")" expression + * : "while" "(" element ")" element * ; */ private void parseWhile() { @@ -1168,7 +1168,7 @@ public class JetExpressionParsing extends AbstractJetParsing { /* * for - * : "for" "(" attributes valOrVar? SimpleName (":" type)? "in" expression ")" expression + * : "for" "(" attributes valOrVar? SimpleName (":" type)? "in" element ")" element * ; * * TODO: empty loop body (at the end of the block)? @@ -1207,7 +1207,7 @@ public class JetExpressionParsing extends AbstractJetParsing { } /* - * expression + * element */ private void parseControlStructureBody() { PsiBuilder.Marker body = mark(); @@ -1263,7 +1263,7 @@ public class JetExpressionParsing extends AbstractJetParsing { /* * if - * : "if" "(" expression ")" expression SEMI? ("else" expression)? + * : "if" "(" element ")" element SEMI? ("else" element)? * ; */ private void parseIf() { @@ -1296,7 +1296,7 @@ public class JetExpressionParsing extends AbstractJetParsing { } /* - * "(" expression ")" + * "(" element ")" */ private void parseCondition() { myBuilder.disableNewlines(); @@ -1321,13 +1321,13 @@ public class JetExpressionParsing extends AbstractJetParsing { advance(); // BREAK_KEYWORD or CONTINUE_KEYWORD - if (!eol() && atSet(LABELS)) advance(); // LABELS + parseLabel(); marker.done(type); } /* - * "return" getEntryPoint? expression? + * "return" getEntryPoint? element? */ private void parseReturn() { assert _at(RETURN_KEYWORD); @@ -1336,9 +1336,7 @@ public class JetExpressionParsing extends AbstractJetParsing { advance(); // RETURN_KEYWORD - if (atSet(LABELS)) { - advance(); // LABELS - } + parseLabel(); if (atSet(EXPRESSION_FIRST) && !at(EOL_OR_SEMICOLON)) parseExpression(); @@ -1346,7 +1344,22 @@ public class JetExpressionParsing extends AbstractJetParsing { } /* - * : "throw" expression + * labels + */ + private void parseLabel() { + if (!eol() && atSet(LABELS)) { + PsiBuilder.Marker labelWrap = mark(); + + PsiBuilder.Marker mark = mark(); + advance(); // LABELS + mark.done(LABEL_REFERENCE); + + labelWrap.done(LABEL_QUALIFIER); + } + } + + /* + * : "throw" element */ private void parseThrow() { assert _at(THROW_KEYWORD); @@ -1379,7 +1392,7 @@ public class JetExpressionParsing extends AbstractJetParsing { } /* - * "typeof" "(" expression ")" + * "typeof" "(" element ")" */ private void parseTypeOf() { assert _at(TYPEOF_KEYWORD); @@ -1399,13 +1412,13 @@ public class JetExpressionParsing extends AbstractJetParsing { } /* - * tupleLiteral // Ambiguity when after a SimpleName (infix call). In this case (e) is treated as an expression in parentheses + * tupleLiteral // Ambiguity when after a SimpleName (infix call). In this case (e) is treated as an element in parentheses * // to put a tuple, write write ((e)) - * : "(" ((SimpleName "=")? expression){","} ")" + * : "(" ((SimpleName "=")? element){","} ")" * ; * - * expression - * : "(" expression ")" + * element + * : "(" element ")" * ; * * TODO: duplication with valueArguments (but for the error messages) @@ -1422,7 +1435,7 @@ public class JetExpressionParsing extends AbstractJetParsing { while (true) { while (at(COMMA)) { tuple = true; - errorAndAdvance("Expecting a tuple entry (expression)"); + errorAndAdvance("Expecting a tuple entry (element)"); } if (at(IDENTIFIER) && lookahead(1) == EQ) { @@ -1441,7 +1454,7 @@ public class JetExpressionParsing extends AbstractJetParsing { tuple = true; if (at(RPAR)) { - error("Expecting a tuple entry (expression)"); + error("Expecting a tuple entry (element)"); break; } } @@ -1463,11 +1476,7 @@ public class JetExpressionParsing extends AbstractJetParsing { PsiBuilder.Marker mark = mark(); advance(); // THIS_KEYWORD - if (atSet(LABELS)) { - PsiBuilder.Marker label = mark(); - advance(); // LABELS - label.done(LABEL_REFERENCE); - } + parseLabel(); if (at(LT)) { // This may be "this < foo" or "this", thus the backtracking @@ -1492,7 +1501,7 @@ public class JetExpressionParsing extends AbstractJetParsing { /* * valueArguments - * : "(" (SimpleName "=")? ("out" | "ref")? expression{","} ")" + * : "(" (SimpleName "=")? ("out" | "ref")? element{","} ")" * ; */ public void parseValueArgumentList() { @@ -1521,7 +1530,7 @@ public class JetExpressionParsing extends AbstractJetParsing { } /* - * (SimpleName "=")? ("out" | "ref")? expression + * (SimpleName "=")? ("out" | "ref")? element */ private void parseValueArgument() { PsiBuilder.Marker argument = mark(); diff --git a/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java b/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java index 4d2ae02a97c..ee9ead31aa2 100644 --- a/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java +++ b/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java @@ -311,7 +311,7 @@ public class JetParsing extends AbstractJetParsing { /* * attribute - * // : SimpleName{"."} (valueArguments | "=" expression)? + * // : SimpleName{"."} (valueArguments | "=" element)? * [for recovery: userType valueArguments?] * ; */ @@ -683,7 +683,7 @@ public class JetParsing extends AbstractJetParsing { * : modifiers ("val" | "var") * typeParameters? (type "." | attributes)? * SimpleName (":" type)? - * ("=" expression SEMI?)? + * ("=" element SEMI?)? * (getter? setter? | setter? getter?) SEMI? * ; */ @@ -883,7 +883,7 @@ public class JetParsing extends AbstractJetParsing { /* * functionBody * : block - * : "=" expression + * : "=" element * ; */ private void parseFunctionBody() { @@ -975,7 +975,7 @@ public class JetParsing extends AbstractJetParsing { * ; * * explicitDelegation - * : userType "by" expression + * : userType "by" element * ; */ private void parseDelegationSpecifier() { @@ -1336,7 +1336,7 @@ public class JetParsing extends AbstractJetParsing { * ; * * functionParameterRest - * : parameter ("=" expression)? + * : parameter ("=" element)? * ; */ public void parseValueParameterList(boolean isFunctionTypeContents, TokenSet recoverySet) { @@ -1376,7 +1376,7 @@ public class JetParsing extends AbstractJetParsing { /* * functionParameter - * : modifiers ("val" | "var")? parameter ("=" expression)? + * : modifiers ("val" | "var")? parameter ("=" element)? * ; */ private boolean tryParseValueParameter() { @@ -1408,7 +1408,7 @@ public class JetParsing extends AbstractJetParsing { /* * functionParameterRest - * : parameter ("=" expression)? + * : parameter ("=" element)? * ; */ private boolean parseFunctionParameterRest() { diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetContainerNode.java b/idea/src/org/jetbrains/jet/lang/psi/JetContainerNode.java index 16eae226a81..df0294c4a5d 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetContainerNode.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetContainerNode.java @@ -1,6 +1,8 @@ package org.jetbrains.jet.lang.psi; import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; +import com.intellij.psi.tree.IElementType; import org.jetbrains.annotations.NotNull; /** @@ -15,4 +17,9 @@ public class JetContainerNode extends JetElement { protected T findChildByClass(Class aClass) { return super.findChildByClass(aClass); } + + @Override // for visibility + protected PsiElement findChildByType(IElementType type) { + return super.findChildByType(type); + } } diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetContinueExpression.java b/idea/src/org/jetbrains/jet/lang/psi/JetContinueExpression.java index 72fbe3bacc3..64053f7d7f7 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetContinueExpression.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetContinueExpression.java @@ -1,10 +1,7 @@ package org.jetbrains.jet.lang.psi; import com.intellij.lang.ASTNode; -import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lexer.JetTokens; /** * @author max @@ -19,9 +16,4 @@ public class JetContinueExpression extends JetLabelQualifiedExpression { visitor.visitContinueExpression(this); } - @Nullable - public String getLabelName() { - PsiElement id = findChildByType(JetTokens.IDENTIFIER); - return id != null ? id.getText() : null; - } } diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetLabelQualifiedExpression.java b/idea/src/org/jetbrains/jet/lang/psi/JetLabelQualifiedExpression.java index c6ce9d39988..ef7286ebae1 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetLabelQualifiedExpression.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetLabelQualifiedExpression.java @@ -3,7 +3,7 @@ package org.jetbrains.jet.lang.psi; import com.intellij.lang.ASTNode; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lexer.JetTokens; +import org.jetbrains.jet.JetNodeTypes; /** * @author abreslav @@ -16,7 +16,9 @@ public class JetLabelQualifiedExpression extends JetExpression { @Nullable public JetSimpleNameExpression getTargetLabel() { - return (JetSimpleNameExpression) findChildByType(JetTokens.LABELS); + JetContainerNode qualifier = (JetContainerNode) findChildByType(JetNodeTypes.LABEL_QUALIFIER); + if (qualifier == null) return null; + return (JetSimpleNameExpression) qualifier.findChildByType(JetNodeTypes.LABEL_REFERENCE); } @Nullable @IfNotParsed diff --git a/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java b/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java index 8c025bacbaa..417d9dca55f 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java @@ -14,6 +14,7 @@ import java.util.Map; public class BindingTraceContext extends BindingTrace implements BindingContext { private final Map expressionTypes = new HashMap(); private final Map resolutionResults = new HashMap(); + private final Map labelResolutionResults = new HashMap(); private final Map types = new HashMap(); private final Map descriptorToDeclarations = new HashMap(); private final Map declarationsToDescriptors = new HashMap(); @@ -31,6 +32,11 @@ public class BindingTraceContext extends BindingTrace implements BindingContext resolutionResults.put(expression, descriptor); } + @Override + public void recordLabelResolution(@NotNull JetReferenceExpression expression, @NotNull PsiElement element) { + labelResolutionResults.put(expression, element); + } + @Override public void removeReferenceResolution(@NotNull JetReferenceExpression referenceExpression) { resolutionResults.remove(referenceExpression); @@ -107,7 +113,7 @@ public class BindingTraceContext extends BindingTrace implements BindingContext public PsiElement resolveToDeclarationPsiElement(JetReferenceExpression referenceExpression) { DeclarationDescriptor declarationDescriptor = resolveReferenceExpression(referenceExpression); if (declarationDescriptor == null) { - return null; + return labelResolutionResults.get(referenceExpression); } return descriptorToDeclarations.get(declarationDescriptor.getOriginal()); } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java index 33166e3a92b..b3367150998 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java @@ -177,7 +177,7 @@ public class ClassDescriptorResolver { } } else { if (bodyExpression == null) { - semanticServices.getErrorHandler().genericError(function.getNode(), "This function must either declare a return type or have a body expression"); + semanticServices.getErrorHandler().genericError(function.getNode(), "This function must either declare a return type or have a body element"); returnType = ErrorUtils.createErrorType("No type, no body"); } else { // TODO : Recursion possible diff --git a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index 16d9a1ce5b3..67a58cd7cd4 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -234,7 +234,7 @@ public class TopDownAnalyzer { if (bodyExpression != null) { System.out.println("-------------"); JetControlFlowInstructionsGenerator instructionsGenerator = new JetControlFlowInstructionsGenerator(); - new JetControlFlowProcessor(semanticServices, instructionsGenerator).generate(function, bodyExpression); + new JetControlFlowProcessor(semanticServices, trace, instructionsGenerator).generate(function, bodyExpression); Pseudocode pseudocode = instructionsGenerator.getPseudocode(); pseudocode.postProcess(); pseudocode.dumpInstructions(System.out); diff --git a/idea/src/org/jetbrains/jet/lang/types/BindingTrace.java b/idea/src/org/jetbrains/jet/lang/types/BindingTrace.java index 30394e46f96..171cd9f3f9b 100644 --- a/idea/src/org/jetbrains/jet/lang/types/BindingTrace.java +++ b/idea/src/org/jetbrains/jet/lang/types/BindingTrace.java @@ -18,6 +18,10 @@ public class BindingTrace { } + public void recordLabelResolution(@NotNull JetReferenceExpression expression, @NotNull PsiElement element) { + + } + public void recordDeclarationResolution(@NotNull PsiElement declaration, @NotNull DeclarationDescriptor descriptor) { } diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index a973548efd3..25cc86b6b2d 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -185,7 +185,7 @@ public class JetTypeInferrer { @Override public void visitJetElement(JetElement elem) { - semanticServices.getErrorHandler().genericError(elem.getNode(), "Unsupported in call expression"); // TODO : Message + semanticServices.getErrorHandler().genericError(elem.getNode(), "Unsupported in call element"); // TODO : Message } }); return wrapForTracing(result[0], reference[0], argumentList, true); @@ -894,7 +894,7 @@ public class JetTypeInferrer { } else if (selectorExpression != null) { // TODO : not a simple name -> resolve in scope, expect property type or a function type - semanticServices.getErrorHandler().genericError(selectorExpression.getNode(), "Unsupported selector expression type: " + selectorExpression); + semanticServices.getErrorHandler().genericError(selectorExpression.getNode(), "Unsupported selector element type: " + selectorExpression); } return receiverType; } @@ -1312,7 +1312,7 @@ public class JetTypeInferrer { String counterpartName = binaryOperationNames.get(assignmentOperationCounterparts.get(operationType)); getTypeForBinaryCall(expression, counterpartName, scope, true); } - result = null; // not an expression + result = null; // not an element } @Override @@ -1335,7 +1335,7 @@ public class JetTypeInferrer { } } } - result = null; // This is not an expression + result = null; // This is not an element } private void resolveArrayAccessToLValue(JetArrayAccessExpression arrayAccessExpression, JetExpression rightHandSide, JetSimpleNameExpression operationSign) { diff --git a/idea/src/org/jetbrains/jet/lexer/_JetLexer.java b/idea/src/org/jetbrains/jet/lexer/_JetLexer.java index 5a09986d6b4..cf78da8b5e8 100644 --- a/idea/src/org/jetbrains/jet/lexer/_JetLexer.java +++ b/idea/src/org/jetbrains/jet/lexer/_JetLexer.java @@ -640,7 +640,7 @@ class _JetLexer implements FlexLexer { /** - * Returns the text matched by the current regular expression. + * Returns the text matched by the current regular element. */ public final CharSequence yytext() { return zzBuffer.subSequence(zzStartRead, zzMarkedPos); @@ -727,7 +727,7 @@ class _JetLexer implements FlexLexer { /** - * Resumes scanning until the next regular expression is matched, + * Resumes scanning until the next regular element is matched, * the end of input is encountered or an I/O-Error occurs. * * @return the next token diff --git a/idea/testData/psi/Expressions_ERR.txt b/idea/testData/psi/Expressions_ERR.txt index c585b07d936..23db544c3f5 100644 --- a/idea/testData/psi/Expressions_ERR.txt +++ b/idea/testData/psi/Expressions_ERR.txt @@ -30,17 +30,17 @@ JetFile: Expressions_ERR.jet REFERENCE_EXPRESSION PsiElement(IDENTIFIER)('dfsd') PsiWhiteSpace('\n ') - PsiErrorElement:Expecting an expression + PsiErrorElement:Expecting an element PsiElement(RPAR)(')') PsiElement(SEMICOLON)(';') PsiElement(SEMICOLON)(';') PsiElement(SEMICOLON)(';') - PsiErrorElement:Expecting an expression + PsiErrorElement:Expecting an element PsiElement(RPAR)(')') PsiElement(SEMICOLON)(';') PsiElement(SEMICOLON)(';') PsiElement(SEMICOLON)(';') - PsiErrorElement:Expecting an expression + PsiErrorElement:Expecting an element PsiElement(BAD_CHARACTER)('~') PsiElement(SEMICOLON)(';') PsiElement(SEMICOLON)(';') @@ -49,10 +49,10 @@ JetFile: Expressions_ERR.jet REFERENCE_EXPRESSION PsiElement(IDENTIFIER)('srgsdfg') PsiWhiteSpace('\n\n ') - PsiErrorElement:Expecting an expression + PsiErrorElement:Expecting an element PsiElement(BAD_CHARACTER)('~') PsiWhiteSpace('\n\n ') - PsiErrorElement:Expecting an expression + PsiErrorElement:Expecting an element PsiElement(RBRACKET)(']') PsiWhiteSpace('\n') PsiElement(RBRACE)('}') \ No newline at end of file diff --git a/idea/testData/psi/When_ERR.txt b/idea/testData/psi/When_ERR.txt index 34b37ef5fc3..c24ea00ca74 100644 --- a/idea/testData/psi/When_ERR.txt +++ b/idea/testData/psi/When_ERR.txt @@ -60,7 +60,7 @@ JetFile: When_ERR.jet WHEN_ENTRY WHEN_CONDITION PsiElement(in)('in') - PsiErrorElement:Expecting an expression + PsiErrorElement:Expecting an element PsiWhiteSpace(' ') PsiElement(DOUBLE_ARROW)('=>') @@ -71,7 +71,7 @@ JetFile: When_ERR.jet WHEN_ENTRY WHEN_CONDITION PsiElement(NOT_IN)('!in') - PsiErrorElement:Expecting an expression + PsiErrorElement:Expecting an element PsiWhiteSpace(' ') PsiElement(DOUBLE_ARROW)('=>') @@ -81,7 +81,7 @@ JetFile: When_ERR.jet PsiWhiteSpace('\n ') WHEN_ENTRY WHEN_CONDITION - PsiErrorElement:Expecting an expression, is-condition or in-condition + PsiErrorElement:Expecting an element, is-condition or in-condition PsiElement(DOUBLE_ARROW)('=>') PsiWhiteSpace(' ') @@ -90,7 +90,7 @@ JetFile: When_ERR.jet PsiWhiteSpace('\n ') WHEN_ENTRY PsiElement(else)('else') - PsiErrorElement:Expecting 'continue' or '=> expression' + PsiErrorElement:Expecting 'continue' or '=> element' PsiWhiteSpace('\n ') PsiElement(RBRACE)('}') @@ -112,7 +112,7 @@ JetFile: When_ERR.jet PsiWhiteSpace(' ') PsiElement(DOUBLE_ARROW)('=>') - PsiErrorElement:Expecting an expression + PsiErrorElement:Expecting an element PsiWhiteSpace('\n ') WHEN_ENTRY @@ -122,59 +122,59 @@ JetFile: When_ERR.jet PsiWhiteSpace(' ') PsiElement(DOUBLE_ARROW)('=>') - PsiErrorElement:Expecting an expression + PsiErrorElement:Expecting an element PsiWhiteSpace('\n ') WHEN_ENTRY WHEN_CONDITION PsiElement(in)('in') - PsiErrorElement:Expecting an expression + PsiErrorElement:Expecting an element PsiWhiteSpace(' ') PsiElement(DOUBLE_ARROW)('=>') - PsiErrorElement:Expecting an expression + PsiErrorElement:Expecting an element PsiWhiteSpace('\n ') WHEN_ENTRY WHEN_CONDITION PsiElement(NOT_IN)('!in') - PsiErrorElement:Expecting an expression + PsiErrorElement:Expecting an element PsiWhiteSpace(' ') PsiElement(DOUBLE_ARROW)('=>') - PsiErrorElement:Expecting an expression + PsiErrorElement:Expecting an element PsiWhiteSpace('\n ') WHEN_ENTRY WHEN_CONDITION PsiElement(NOT_IN)('!in') - PsiErrorElement:Expecting an expression + PsiErrorElement:Expecting an element PsiWhiteSpace(' ') PsiElement(DOUBLE_ARROW)('=>') - PsiErrorElement:Expecting an expression + PsiErrorElement:Expecting an element PsiWhiteSpace(' ') PsiElement(SEMICOLON)(';') PsiWhiteSpace('\n ') WHEN_ENTRY WHEN_CONDITION - PsiErrorElement:Expecting an expression, is-condition or in-condition + PsiErrorElement:Expecting an element, is-condition or in-condition PsiElement(DOUBLE_ARROW)('=>') - PsiErrorElement:Expecting an expression + PsiErrorElement:Expecting an element PsiWhiteSpace('\n ') WHEN_ENTRY PsiElement(else)('else') - PsiErrorElement:Expecting 'continue' or '=> expression' + PsiErrorElement:Expecting 'continue' or '=> element' PsiWhiteSpace('\n ') WHEN_ENTRY PsiElement(else)('else') PsiWhiteSpace(' ') PsiElement(DOUBLE_ARROW)('=>') - PsiErrorElement:Expecting an expression + PsiErrorElement:Expecting an element PsiWhiteSpace('\n ') PsiElement(RBRACE)('}')