Merge remote branch 'origin/master'
This commit is contained in:
@@ -1462,7 +1462,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
return StackValue.onStack(Type.BOOLEAN_TYPE);
|
||||
}
|
||||
|
||||
private StackValue generateEqualsForExpressionsOnStack(IElementType opToken, Type leftType, Type rightType, boolean leftNullable, boolean rightNullable) {
|
||||
public StackValue generateEqualsForExpressionsOnStack(IElementType opToken, Type leftType, Type rightType, boolean leftNullable, boolean rightNullable) {
|
||||
if (isNumberPrimitive(leftType) && leftType == rightType) {
|
||||
return compareExpressionsOnStack(opToken, leftType);
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ public class JetTypeMapper {
|
||||
public static final Type JL_BOOLEAN_TYPE = Type.getObjectType("java/lang/Boolean");
|
||||
public static final Type JL_NUMBER_TYPE = Type.getObjectType("java/lang/Number");
|
||||
public static final Type JL_STRING_BUILDER = Type.getObjectType("java/lang/StringBuilder");
|
||||
public static final Type JL_STRING_TYPE = Type.getObjectType("java/lang/String");
|
||||
|
||||
public static final Type ARRAY_INT_TYPE = Type.getType(int[].class);
|
||||
public static final Type ARRAY_LONG_TYPE = Type.getType(long[].class);
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package org.jetbrains.jet.codegen.intrinsics;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import org.jetbrains.jet.codegen.ExpressionCodegen;
|
||||
import org.jetbrains.jet.codegen.JetTypeMapper;
|
||||
import org.jetbrains.jet.codegen.StackValue;
|
||||
import org.jetbrains.jet.lang.psi.JetCallExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author alex.tkachman
|
||||
*/
|
||||
public class Equals implements IntrinsicMethod {
|
||||
@Override
|
||||
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, StackValue receiver) {
|
||||
receiver.put(JetTypeMapper.TYPE_OBJECT, v);
|
||||
|
||||
boolean leftNullable = true;
|
||||
if(element instanceof JetCallExpression) {
|
||||
JetCallExpression jetCallExpression = (JetCallExpression) element;
|
||||
JetExpression calleeExpression = jetCallExpression.getCalleeExpression();
|
||||
if(calleeExpression != null) {
|
||||
JetType leftType = codegen.getBindingContext().get(BindingContext.EXPRESSION_TYPE, calleeExpression);
|
||||
if(leftType != null)
|
||||
leftNullable = leftType.isNullable();
|
||||
}
|
||||
}
|
||||
|
||||
JetExpression rightExpr = arguments.get(0);
|
||||
JetType rightType = codegen.getBindingContext().get(BindingContext.EXPRESSION_TYPE, rightExpr);
|
||||
codegen.gen(rightExpr).put(JetTypeMapper.TYPE_OBJECT, v);
|
||||
|
||||
return codegen.generateEqualsForExpressionsOnStack(JetTokens.EQEQ, JetTypeMapper.TYPE_OBJECT, JetTypeMapper.TYPE_OBJECT, leftNullable, rightType.isNullable());
|
||||
}
|
||||
}
|
||||
@@ -73,6 +73,11 @@ public class IntrinsicMethods {
|
||||
|
||||
declareIntrinsicFunction("String", "plus", 1, new Concat());
|
||||
|
||||
declareOverload(myStdLib.getLibraryScope().getFunctions("toString"), 0, new ToString());
|
||||
declareOverload(myStdLib.getLibraryScope().getFunctions("equals"), 1, new Equals());
|
||||
|
||||
// declareIntrinsicFunction("Any", "equals", 1, new Equals());
|
||||
//
|
||||
declareIntrinsicStringMethods();
|
||||
declareIntrinsicProperty("String", "length", new StringLength());
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.jetbrains.jet.codegen.intrinsics;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.jet.codegen.ExpressionCodegen;
|
||||
import org.jetbrains.jet.codegen.JetTypeMapper;
|
||||
import org.jetbrains.jet.codegen.StackValue;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.types.JetStandardClasses;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author alex.tkachman
|
||||
*/
|
||||
public class ToString implements IntrinsicMethod {
|
||||
@Override
|
||||
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, StackValue receiver) {
|
||||
receiver.put(JetTypeMapper.TYPE_OBJECT, v);
|
||||
v.invokestatic("java/lang/String", "valueOf", "(Ljava/lang/Object;)Ljava/lang/String;");
|
||||
return StackValue.onStack(JetTypeMapper.JL_STRING_TYPE);
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiDirectory;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import org.jetbrains.jet.codegen.ClassFileFactory;
|
||||
@@ -28,12 +29,13 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
* @author alex.tkachman
|
||||
*/
|
||||
public class KotlinCompiler {
|
||||
public static void main(String[] args) {
|
||||
System.setProperty("java.awt.headless", "true");
|
||||
if (args.length < 1) {
|
||||
System.out.println("Usage: KotlinCompiler <filename>");
|
||||
System.out.println("Usage: KotlinCompiler <filename> or <dirname>");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -44,61 +46,36 @@ public class KotlinCompiler {
|
||||
};
|
||||
JavaCoreEnvironment environment = new JavaCoreEnvironment(root);
|
||||
|
||||
String javaHome = System.getenv("JAVA_HOME");
|
||||
File rtJar = null;
|
||||
if (javaHome == null) {
|
||||
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
|
||||
if(systemClassLoader instanceof URLClassLoader) {
|
||||
URLClassLoader loader = (URLClassLoader) systemClassLoader;
|
||||
for(URL url: loader.getURLs()) {
|
||||
if("file".equals(url.getProtocol())) {
|
||||
if(url.getFile().endsWith("/lib/rt.jar")) {
|
||||
rtJar = new File(url.getFile());
|
||||
break;
|
||||
}
|
||||
if(url.getFile().endsWith("/Classes/classes.jar")) {
|
||||
rtJar = new File(url.getFile()).getAbsoluteFile();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(rtJar == null) {
|
||||
System.out.println("JAVA_HOME environment variable needs to be defined");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
rtJar = findRtJar(javaHome);
|
||||
}
|
||||
|
||||
if (rtJar == null || !rtJar.exists()) {
|
||||
System.out.print("No rt.jar found under JAVA_HOME=" + javaHome);
|
||||
return;
|
||||
}
|
||||
File rtJar = initJdk();
|
||||
if (rtJar == null) return;
|
||||
|
||||
environment.addToClasspath(rtJar);
|
||||
|
||||
environment.registerFileType(JetFileType.INSTANCE, "kt");
|
||||
environment.registerFileType(JetFileType.INSTANCE, "jet");
|
||||
environment.registerParserDefinition(new JetParserDefinition());
|
||||
|
||||
VirtualFile vFile = environment.getLocalFileSystem().findFileByPath(args [0]);
|
||||
if (vFile == null) {
|
||||
System.out.print("File not found: " + args[0]);
|
||||
System.out.print("File/directory not found: " + args[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
Project project = environment.getProject();
|
||||
GenerationState generationState = new GenerationState(project, false);
|
||||
List<JetNamespace> namespaces = Lists.newArrayList();
|
||||
PsiFile psiFile = PsiManager.getInstance(project).findFile(vFile);
|
||||
if (psiFile instanceof JetFile) {
|
||||
namespaces.add(((JetFile) psiFile).getRootNamespace());
|
||||
if(vFile.isDirectory()) {
|
||||
File dir = new File(vFile.getPath());
|
||||
addFiles(environment, project, namespaces, dir);
|
||||
}
|
||||
else {
|
||||
System.out.print("Not a Kotlin file: " + vFile.getPath());
|
||||
return;
|
||||
PsiFile psiFile = PsiManager.getInstance(project).findFile(vFile);
|
||||
if (psiFile instanceof JetFile) {
|
||||
namespaces.add(((JetFile) psiFile).getRootNamespace());
|
||||
}
|
||||
else {
|
||||
System.out.print("Not a Kotlin file: " + vFile.getPath());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
BindingContext bindingContext = AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS).analyzeNamespaces(project, namespaces, JetControlFlowDataTraceFactory.EMPTY);
|
||||
@@ -137,6 +114,59 @@ public class KotlinCompiler {
|
||||
|
||||
}
|
||||
|
||||
private static void addFiles(JavaCoreEnvironment environment, Project project, List<JetNamespace> namespaces, File dir) {
|
||||
for(File file : dir.listFiles()) {
|
||||
if(!file.isDirectory()) {
|
||||
VirtualFile virtualFile = environment.getLocalFileSystem().findFileByPath(file.getAbsolutePath());
|
||||
PsiFile psiFile = PsiManager.getInstance(project).findFile(virtualFile);
|
||||
if (psiFile instanceof JetFile) {
|
||||
namespaces.add(((JetFile) psiFile).getRootNamespace());
|
||||
System.out.println(file.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
else {
|
||||
addFiles(environment, project, namespaces, file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static File initJdk() {
|
||||
String javaHome = System.getenv("JAVA_HOME");
|
||||
File rtJar = null;
|
||||
if (javaHome == null) {
|
||||
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
|
||||
if(systemClassLoader instanceof URLClassLoader) {
|
||||
URLClassLoader loader = (URLClassLoader) systemClassLoader;
|
||||
for(URL url: loader.getURLs()) {
|
||||
if("file".equals(url.getProtocol())) {
|
||||
if(url.getFile().endsWith("/lib/rt.jar")) {
|
||||
rtJar = new File(url.getFile());
|
||||
break;
|
||||
}
|
||||
if(url.getFile().endsWith("/Classes/classes.jar")) {
|
||||
rtJar = new File(url.getFile()).getAbsoluteFile();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(rtJar == null) {
|
||||
System.out.println("JAVA_HOME environment variable needs to be defined");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
rtJar = findRtJar(javaHome);
|
||||
}
|
||||
|
||||
if (rtJar == null || !rtJar.exists()) {
|
||||
System.out.print("No rt.jar found under JAVA_HOME=" + javaHome);
|
||||
return null;
|
||||
}
|
||||
return rtJar;
|
||||
}
|
||||
|
||||
private static void report(Diagnostic diagnostic) {
|
||||
System.out.println(diagnostic.getMessage());
|
||||
}
|
||||
|
||||
@@ -21,18 +21,12 @@ public class JetSemanticServices {
|
||||
return new JetSemanticServices(JetStandardLibrary.getJetStandardLibrary(project), JetControlFlowDataTraceFactory.EMPTY);
|
||||
}
|
||||
|
||||
public static JetSemanticServices createSemanticServices(Project project, JetControlFlowDataTraceFactory flowDataTraceFactory) {
|
||||
return new JetSemanticServices(JetStandardLibrary.getJetStandardLibrary(project), flowDataTraceFactory);
|
||||
}
|
||||
|
||||
private final JetStandardLibrary standardLibrary;
|
||||
private final JetTypeChecker typeChecker;
|
||||
private final JetControlFlowDataTraceFactory flowDataTraceFactory;
|
||||
|
||||
private JetSemanticServices(JetStandardLibrary standardLibrary, JetControlFlowDataTraceFactory flowDataTraceFactory) {
|
||||
this.standardLibrary = standardLibrary;
|
||||
this.typeChecker = new JetTypeChecker(standardLibrary);
|
||||
this.flowDataTraceFactory = flowDataTraceFactory;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -42,7 +36,7 @@ public class JetSemanticServices {
|
||||
|
||||
@NotNull
|
||||
public ClassDescriptorResolver getClassDescriptorResolver(BindingTrace trace) {
|
||||
return new ClassDescriptorResolver(this, trace, flowDataTraceFactory);
|
||||
return new ClassDescriptorResolver(this, trace);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -2,9 +2,9 @@ package org.jetbrains.jet.lang.cfg;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetThrowExpression;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
@@ -24,6 +24,7 @@ public interface JetControlFlowBuilder {
|
||||
void jumpOnFalse(@NotNull Label label);
|
||||
void jumpOnTrue(@NotNull Label label);
|
||||
void nondeterministicJump(Label label); // Maybe, jump to label
|
||||
void nondeterministicJump(List<Label> label);
|
||||
void jumpToError(JetThrowExpression expression);
|
||||
void jumpToError(JetExpression nothingExpression);
|
||||
|
||||
@@ -43,9 +44,9 @@ public interface JetControlFlowBuilder {
|
||||
void exitTryFinally();
|
||||
|
||||
// Subroutines
|
||||
void enterSubroutine(@NotNull JetElement subroutine, boolean isFunctionLiteral);
|
||||
void enterSubroutine(@NotNull JetDeclaration subroutine);
|
||||
|
||||
void exitSubroutine(@NotNull JetElement subroutine, boolean functionLiteral);
|
||||
void exitSubroutine(@NotNull JetDeclaration subroutine);
|
||||
|
||||
@Nullable
|
||||
JetElement getCurrentSubroutine();
|
||||
|
||||
+38
-12
@@ -2,140 +2,166 @@ package org.jetbrains.jet.lang.cfg;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetThrowExpression;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class JetControlFlowBuilderAdapter implements JetControlFlowBuilder {
|
||||
protected JetControlFlowBuilder builder;
|
||||
|
||||
public JetControlFlowBuilderAdapter(JetControlFlowBuilder builder) {
|
||||
this.builder = builder;
|
||||
}
|
||||
protected @Nullable JetControlFlowBuilder builder;
|
||||
|
||||
@Override
|
||||
public void read(@NotNull JetExpression expression) {
|
||||
assert builder != null;
|
||||
builder.read(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readUnit(@NotNull JetExpression expression) {
|
||||
assert builder != null;
|
||||
builder.readUnit(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Label createUnboundLabel() {
|
||||
assert builder != null;
|
||||
return builder.createUnboundLabel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindLabel(@NotNull Label label) {
|
||||
assert builder != null;
|
||||
builder.bindLabel(label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jump(@NotNull Label label) {
|
||||
assert builder != null;
|
||||
builder.jump(label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jumpOnFalse(@NotNull Label label) {
|
||||
assert builder != null;
|
||||
builder.jumpOnFalse(label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jumpOnTrue(@NotNull Label label) {
|
||||
assert builder != null;
|
||||
builder.jumpOnTrue(label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nondeterministicJump(Label label) {
|
||||
assert builder != null;
|
||||
builder.nondeterministicJump(label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nondeterministicJump(List<Label> labels) {
|
||||
assert builder != null;
|
||||
builder.nondeterministicJump(labels);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jumpToError(JetThrowExpression expression) {
|
||||
assert builder != null;
|
||||
builder.jumpToError(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jumpToError(JetExpression nothingExpression) {
|
||||
assert builder != null;
|
||||
builder.jumpToError(nothingExpression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Label getEntryPoint(@NotNull JetElement labelElement) {
|
||||
assert builder != null;
|
||||
return builder.getEntryPoint(labelElement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Label getExitPoint(@NotNull JetElement labelElement) {
|
||||
assert builder != null;
|
||||
return builder.getExitPoint(labelElement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoopInfo enterLoop(@NotNull JetExpression expression, Label loopExitPoint, Label conditionEntryPoint) {
|
||||
assert builder != null;
|
||||
return builder.enterLoop(expression, loopExitPoint, conditionEntryPoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitLoop(@NotNull JetExpression expression) {
|
||||
assert builder != null;
|
||||
builder.exitLoop(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public JetElement getCurrentLoop() {
|
||||
assert builder != null;
|
||||
return builder.getCurrentLoop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterTryFinally(@NotNull GenerationTrigger trigger) {
|
||||
assert builder != null;
|
||||
builder.enterTryFinally(trigger);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitTryFinally() {
|
||||
assert builder != null;
|
||||
builder.exitTryFinally();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterSubroutine(@NotNull JetElement subroutine, boolean isFunctionLiteral) {
|
||||
builder.enterSubroutine(subroutine, isFunctionLiteral);
|
||||
public void enterSubroutine(@NotNull JetDeclaration subroutine) {
|
||||
assert builder != null;
|
||||
builder.enterSubroutine(subroutine);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitSubroutine(@NotNull JetElement subroutine, boolean functionLiteral) {
|
||||
builder.exitSubroutine(subroutine, functionLiteral);
|
||||
public void exitSubroutine(@NotNull JetDeclaration subroutine) {
|
||||
assert builder != null;
|
||||
builder.exitSubroutine(subroutine);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public JetElement getCurrentSubroutine() {
|
||||
assert builder != null;
|
||||
return builder.getCurrentSubroutine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void returnValue(@NotNull JetExpression returnExpression, @NotNull JetElement subroutine) {
|
||||
assert builder != null;
|
||||
builder.returnValue(returnExpression, subroutine);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void returnNoValue(@NotNull JetElement returnExpression, @NotNull JetElement subroutine) {
|
||||
assert builder != null;
|
||||
builder.returnNoValue(returnExpression, subroutine);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsupported(JetElement element) {
|
||||
assert builder != null;
|
||||
builder.unsupported(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(@NotNull JetElement assignment, @NotNull JetElement lValue) {
|
||||
assert builder != null;
|
||||
builder.write(assignment, lValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.jetbrains.jet.lang.cfg;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -22,8 +23,6 @@ import static org.jetbrains.jet.lang.diagnostics.Errors.*;
|
||||
*/
|
||||
public class JetControlFlowProcessor {
|
||||
|
||||
// private final Map<String, Stack<JetElement>> labeledElements = new HashMap<String, Stack<JetElement>>();
|
||||
|
||||
private final JetControlFlowBuilder builder;
|
||||
private final BindingTrace trace;
|
||||
|
||||
@@ -32,70 +31,94 @@ public class JetControlFlowProcessor {
|
||||
this.trace = trace;
|
||||
}
|
||||
|
||||
public void generate(@NotNull JetElement subroutineElement, @NotNull JetExpression body) {
|
||||
public void generate(@NotNull JetDeclaration subroutineElement, @NotNull JetExpression body) {
|
||||
generateSubroutineControlFlow(subroutineElement, Collections.singletonList(body));
|
||||
}
|
||||
|
||||
public void generateSubroutineControlFlow(@NotNull JetElement subroutineElement, @NotNull List<? extends JetElement> body) {
|
||||
// if (subroutineElement instanceof JetNamedDeclaration) {
|
||||
// JetNamedDeclaration namedDeclaration = (JetNamedDeclaration) subroutineElement;
|
||||
// enterLabeledElement(JetPsiUtil.safeName(namedDeclaration.getName()), namedDeclaration);
|
||||
// }
|
||||
boolean functionLiteral = subroutineElement instanceof JetFunctionLiteralExpression;
|
||||
builder.enterSubroutine(subroutineElement, functionLiteral);
|
||||
public void generateSubroutineControlFlow(@NotNull JetDeclaration subroutineElement, @NotNull List<? extends JetElement> body) {
|
||||
builder.enterSubroutine(subroutineElement);
|
||||
for (JetElement statement : body) {
|
||||
statement.accept(new CFPVisitor(false));
|
||||
}
|
||||
builder.exitSubroutine(subroutineElement, functionLiteral);
|
||||
builder.exitSubroutine(subroutineElement);
|
||||
}
|
||||
|
||||
// private void enterLabeledElement(@NotNull String labelName, @NotNull JetElement labeledElement) {
|
||||
// Stack<JetElement> stack = labeledElements.get(labelName);
|
||||
// if (stack == null) {
|
||||
// stack = new Stack<JetElement>();
|
||||
// labeledElements.put(labelName, stack);
|
||||
// }
|
||||
// stack.push(labeledElement);
|
||||
// }
|
||||
//
|
||||
// private void exitElement(JetElement element) {
|
||||
// // TODO : really suboptimal
|
||||
// for (Iterator<Map.Entry<String, Stack<JetElement>>> mapIter = labeledElements.entrySet().iterator(); mapIter.hasNext(); ) {
|
||||
// Map.Entry<String, Stack<JetElement>> entry = mapIter.next();
|
||||
// Stack<JetElement> stack = entry.getValue();
|
||||
// for (Iterator<JetElement> stackIter = stack.iterator(); stackIter.hasNext(); ) {
|
||||
// JetElement recorded = stackIter.next();
|
||||
// if (recorded == element) {
|
||||
// stackIter.remove();
|
||||
// }
|
||||
// }
|
||||
// if (stack.isEmpty()) {
|
||||
// mapIter.remove();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// @Nullable
|
||||
// private JetElement resolveLabel(@NotNull String labelName, @NotNull JetSimpleNameExpression labelExpression, boolean reportUnresolved) {
|
||||
// Stack<JetElement> stack = labeledElements.get(labelName);
|
||||
// if (stack == null || stack.isEmpty()) {
|
||||
// if (reportUnresolved) {
|
||||
//// trace.report(UNRESOLVED_REFERENCE.on(labelExpression));
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
// else if (stack.size() > 1) {
|
||||
//// trace.getErrorHandler().genericWarning(labelExpression.getNode(), "There is more than one label with such a name in this scope");
|
||||
//// trace.report(LABEL_NAME_CLASH.on(labelExpression));
|
||||
// }
|
||||
//
|
||||
// JetElement result = stack.peek();
|
||||
//// trace.record(BindingContext.LABEL_TARGET, labelExpression, result);
|
||||
// return result;
|
||||
// }
|
||||
|
||||
|
||||
private class CFPVisitor extends JetVisitorVoid {
|
||||
private final boolean inCondition;
|
||||
private final JetVisitorVoid conditionVisitor = new JetVisitorVoid() {
|
||||
@Override
|
||||
public void visitWhenConditionCall(JetWhenConditionCall condition) {
|
||||
value(condition.getCallSuffixExpression(), CFPVisitor.this.inCondition); // TODO : inCondition?
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitWhenConditionInRange(JetWhenConditionInRange condition) {
|
||||
value(condition.getRangeExpression(), CFPVisitor.this.inCondition); // TODO : inCondition?
|
||||
value(condition.getOperationReference(), CFPVisitor.this.inCondition); // TODO : inCondition?
|
||||
// TODO : read the call to contains()...
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitWhenConditionIsPattern(JetWhenConditionIsPattern condition) {
|
||||
JetPattern pattern = condition.getPattern();
|
||||
if (pattern != null) {
|
||||
pattern.accept(patternVisitor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJetElement(JetElement element) {
|
||||
throw new UnsupportedOperationException("[JetControlFlowProcessor] " + element.toString());
|
||||
}
|
||||
};
|
||||
private final JetVisitorVoid patternVisitor = new JetVisitorVoid() {
|
||||
@Override
|
||||
public void visitTypePattern(JetTypePattern typePattern) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitWildcardPattern(JetWildcardPattern pattern) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitExpressionPattern(JetExpressionPattern pattern) {
|
||||
value(pattern.getExpression(), inCondition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTuplePattern(JetTuplePattern pattern) {
|
||||
List<JetTuplePatternEntry> entries = pattern.getEntries();
|
||||
for (JetTuplePatternEntry entry : entries) {
|
||||
JetPattern entryPattern = entry.getPattern();
|
||||
if (entryPattern != null) {
|
||||
entryPattern.accept(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitDecomposerPattern(JetDecomposerPattern pattern) {
|
||||
value(pattern.getDecomposerExpression(), inCondition);
|
||||
pattern.getArgumentList().accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitBindingPattern(JetBindingPattern pattern) {
|
||||
JetProperty variableDeclaration = pattern.getVariableDeclaration();
|
||||
builder.write(pattern, variableDeclaration);
|
||||
JetWhenCondition condition = pattern.getCondition();
|
||||
if (condition != null) {
|
||||
condition.accept(conditionVisitor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJetElement(JetElement element) {
|
||||
throw new UnsupportedOperationException("[JetControlFlowProcessor] " + element.toString());
|
||||
}
|
||||
};
|
||||
|
||||
private CFPVisitor(boolean inCondition) {
|
||||
this.inCondition = inCondition;
|
||||
@@ -111,7 +134,6 @@ public class JetControlFlowProcessor {
|
||||
visitor = new CFPVisitor(inCondition);
|
||||
}
|
||||
element.accept(visitor);
|
||||
// exitElement(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -124,12 +146,6 @@ public class JetControlFlowProcessor {
|
||||
|
||||
@Override
|
||||
public void visitThisExpression(JetThisExpression expression) {
|
||||
// JetSimpleNameExpression targetLabel = expression.getTargetLabel();
|
||||
// if (targetLabel != null) {
|
||||
// String labelName = expression.getLabelName();
|
||||
// assert labelName != null;
|
||||
// resolveLabel(labelName, targetLabel, false);
|
||||
// }
|
||||
builder.read(expression);
|
||||
}
|
||||
|
||||
@@ -161,7 +177,6 @@ public class JetControlFlowProcessor {
|
||||
private void visitLabeledExpression(@NotNull String labelName, @NotNull JetExpression labeledExpression) {
|
||||
JetExpression deparenthesized = JetPsiUtil.deparenthesize(labeledExpression);
|
||||
if (deparenthesized != null) {
|
||||
// enterLabeledElement(labelName, deparenthesized);
|
||||
value(labeledExpression, inCondition);
|
||||
}
|
||||
}
|
||||
@@ -337,6 +352,10 @@ public class JetControlFlowProcessor {
|
||||
builder.bindLabel(onException);
|
||||
for (Iterator<JetCatchClause> iterator = catchClauses.iterator(); iterator.hasNext(); ) {
|
||||
JetCatchClause catchClause = iterator.next();
|
||||
JetParameter catchParameter = catchClause.getCatchParameter();
|
||||
if (catchParameter != null) {
|
||||
builder.write(catchParameter, catchParameter);
|
||||
}
|
||||
JetExpression catchBody = catchClause.getCatchBody();
|
||||
if (catchBody != null) {
|
||||
value(catchBody, false);
|
||||
@@ -403,6 +422,10 @@ public class JetControlFlowProcessor {
|
||||
if (loopRange != null) {
|
||||
value(loopRange, false);
|
||||
}
|
||||
JetParameter loopParameter = expression.getLoopParameter();
|
||||
if (loopParameter != null) {
|
||||
builder.write(loopParameter, loopParameter);
|
||||
}
|
||||
// TODO : primitive cases
|
||||
Label loopExitPoint = builder.createUnboundLabel();
|
||||
Label conditionEntryPoint = builder.createUnboundLabel();
|
||||
@@ -453,29 +476,16 @@ public class JetControlFlowProcessor {
|
||||
trace.report(NOT_A_LOOP_LABEL.on(expression, targetLabel.getText()));
|
||||
loop = null;
|
||||
}
|
||||
// loop = resolveLabel(labelName, targetLabel, true);
|
||||
// if (!isLoop(loop)) {
|
||||
//// trace.getErrorHandler().genericError(expression.getNode(), "The label '" + targetLabel.getText() + "' does not denote a loop");
|
||||
// trace.report(NOT_A_LOOP_LABEL.on(expression, targetLabel.getText()));
|
||||
// loop = null;
|
||||
// }
|
||||
}
|
||||
else {
|
||||
loop = builder.getCurrentLoop();
|
||||
if (loop == null) {
|
||||
// trace.getErrorHandler().genericError(expression.getNode(), "'break' and 'continue' are only allowed inside a loop");
|
||||
trace.report(BREAK_OR_CONTINUE_OUTSIDE_A_LOOP.on(expression));
|
||||
}
|
||||
}
|
||||
return loop;
|
||||
}
|
||||
|
||||
// private boolean isLoop(JetElement loop) {
|
||||
// return loop instanceof JetWhileExpression ||
|
||||
// loop instanceof JetDoWhileExpression ||
|
||||
// loop instanceof JetForExpression;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public void visitReturnExpression(JetReturnExpression expression) {
|
||||
JetExpression returnedExpression = expression.getReturnedExpression();
|
||||
@@ -495,13 +505,16 @@ public class JetControlFlowProcessor {
|
||||
else {
|
||||
subroutine = null;
|
||||
}
|
||||
//subroutine = resolveLabel(labelName, labelElement, true);
|
||||
}
|
||||
else {
|
||||
subroutine = builder.getCurrentSubroutine();
|
||||
// TODO : a context check
|
||||
}
|
||||
if (subroutine instanceof JetFunction || subroutine instanceof JetFunctionLiteralExpression) {
|
||||
//todo cache JetFunctionLiteral instead
|
||||
if (subroutine instanceof JetFunctionLiteralExpression) {
|
||||
subroutine = ((JetFunctionLiteralExpression) subroutine).getFunctionLiteral();
|
||||
}
|
||||
if (subroutine instanceof JetFunction) {
|
||||
if (returnedExpression == null) {
|
||||
builder.returnNoValue(expression, subroutine);
|
||||
}
|
||||
@@ -538,10 +551,10 @@ public class JetControlFlowProcessor {
|
||||
@Override
|
||||
public void visitFunctionLiteralExpression(JetFunctionLiteralExpression expression) {
|
||||
JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
|
||||
JetBlockExpression bodyExpression = expression.getFunctionLiteral().getBodyExpression();
|
||||
JetBlockExpression bodyExpression = functionLiteral.getBodyExpression();
|
||||
if (bodyExpression != null) {
|
||||
List<JetElement> statements = bodyExpression.getStatements();
|
||||
generateSubroutineControlFlow(expression, statements);
|
||||
generateSubroutineControlFlow(functionLiteral, statements);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -649,8 +662,12 @@ public class JetControlFlowProcessor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIsExpression(JetIsExpression expression) {
|
||||
public void visitIsExpression(final JetIsExpression expression) {
|
||||
value(expression.getLeftHandSide(), inCondition);
|
||||
JetPattern pattern = expression.getPattern();
|
||||
if (pattern != null) {
|
||||
pattern.accept(patternVisitor);
|
||||
}
|
||||
// TODO : builder.read(expression.getPattern());
|
||||
builder.read(expression);
|
||||
}
|
||||
@@ -672,7 +689,6 @@ public class JetControlFlowProcessor {
|
||||
|
||||
if (whenEntry.isElse()) {
|
||||
if (iterator.hasNext()) {
|
||||
// trace.getErrorHandler().genericError(whenEntry.getNode(), "'else' entry must be the last one in a when-expression");
|
||||
trace.report(ELSE_MISPLACED_IN_WHEN.on(whenEntry));
|
||||
}
|
||||
}
|
||||
@@ -682,73 +698,7 @@ public class JetControlFlowProcessor {
|
||||
JetWhenCondition[] conditions = whenEntry.getConditions();
|
||||
for (int i = 0; i < conditions.length; i++) {
|
||||
JetWhenCondition condition = conditions[i];
|
||||
condition.accept(new JetVisitorVoid() {
|
||||
private final JetVisitorVoid conditionVisitor = this;
|
||||
|
||||
@Override
|
||||
public void visitWhenConditionCall(JetWhenConditionCall condition) {
|
||||
value(condition.getCallSuffixExpression(), inCondition); // TODO : inCondition?
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitWhenConditionInRange(JetWhenConditionInRange condition) {
|
||||
value(condition.getRangeExpression(), inCondition); // TODO : inCondition?
|
||||
value(condition.getOperationReference(), inCondition); // TODO : inCondition?
|
||||
// TODO : read the call to contains()...
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitWhenConditionIsPattern(JetWhenConditionIsPattern condition) {
|
||||
JetPattern pattern = condition.getPattern();
|
||||
if (pattern != null) {
|
||||
pattern.accept(new JetVisitorVoid() {
|
||||
@Override
|
||||
public void visitTypePattern(JetTypePattern typePattern) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitWildcardPattern(JetWildcardPattern pattern) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitExpressionPattern(JetExpressionPattern pattern) {
|
||||
value(pattern.getExpression(), inCondition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTuplePattern(JetTuplePattern pattern) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitDecomposerPattern(JetDecomposerPattern pattern) {
|
||||
value(pattern.getDecomposerExpression(), inCondition);
|
||||
pattern.getArgumentList().accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitBindingPattern(JetBindingPattern pattern) {
|
||||
JetWhenCondition condition = pattern.getCondition();
|
||||
if (condition != null) {
|
||||
condition.accept(conditionVisitor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJetElement(JetElement element) {
|
||||
throw new UnsupportedOperationException("[JetControlFlowProcessor] " + element.toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJetElement(JetElement element) {
|
||||
throw new UnsupportedOperationException("[JetControlFlowProcessor] " + element.toString());
|
||||
}
|
||||
});
|
||||
condition.accept(conditionVisitor);
|
||||
if (i + 1 < conditions.length) {
|
||||
builder.nondeterministicJump(bodyLabel);
|
||||
}
|
||||
@@ -769,28 +719,41 @@ public class JetControlFlowProcessor {
|
||||
|
||||
@Override
|
||||
public void visitObjectLiteralExpression(JetObjectLiteralExpression expression) {
|
||||
// List<JetDelegationSpecifier> delegationSpecifiers = expression.getObjectDeclaration().getDelegationSpecifiers();
|
||||
// for (JetDelegationSpecifier delegationSpecifier : delegationSpecifiers) {
|
||||
// if (delegationSpecifier instanceof JetDelegatorByExpressionSpecifier) {
|
||||
// JetDelegatorByExpressionSpecifier specifier = (JetDelegatorByExpressionSpecifier) delegationSpecifier;
|
||||
// JetExpression delegateExpression = specifier.getDelegateExpression();
|
||||
// if (delegateExpression != null) {
|
||||
// value(delegateExpression, false, false);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
value(expression.getObjectDeclaration(), inCondition);
|
||||
builder.read(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitObjectDeclaration(JetObjectDeclaration declaration) {
|
||||
for (JetDelegationSpecifier delegationSpecifier : declaration.getDelegationSpecifiers()) {
|
||||
value(delegationSpecifier, inCondition);
|
||||
Queue<Label> declarationLabels = new LinkedList<Label>();
|
||||
List<JetDeclaration> declarations = declaration.getDeclarations();
|
||||
for (JetDeclaration localDeclaration : declarations) {
|
||||
declarationLabels.add(builder.createUnboundLabel());
|
||||
}
|
||||
for (JetDeclaration jetDeclaration : declaration.getDeclarations()) {
|
||||
FOR_LOCAL_CLASSES.value(jetDeclaration, false);
|
||||
builder.nondeterministicJump(Lists.newArrayList(declarationLabels));
|
||||
for (JetDeclaration localDeclaration : declarations) {
|
||||
if (localDeclaration instanceof JetNamedDeclaration) {
|
||||
if (localDeclaration instanceof JetFunction) {
|
||||
//TODO
|
||||
generate(localDeclaration, ((JetFunction) localDeclaration).getBodyExpression());
|
||||
}
|
||||
else {
|
||||
generate(localDeclaration, localDeclaration);
|
||||
}
|
||||
}
|
||||
else {
|
||||
//todo
|
||||
generate(declaration, localDeclaration);
|
||||
}
|
||||
builder.bindLabel(declarationLabels.remove());
|
||||
}
|
||||
// for (JetDelegationSpecifier delegationSpecifier : declaration.getDelegationSpecifiers()) {
|
||||
// value(delegationSpecifier, inCondition);
|
||||
// }
|
||||
// for (JetDeclaration jetDeclaration : declaration.getDeclarations()) {
|
||||
// //FOR_LOCAL_CLASSES.
|
||||
// value(jetDeclaration, false);
|
||||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,92 +1,391 @@
|
||||
package org.jetbrains.jet.lang.cfg;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetLoopExpression;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.*;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.LocalVariableDescriptor;
|
||||
import org.jetbrains.jet.lang.diagnostics.Errors;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
* @author svtk
|
||||
*/
|
||||
public interface JetFlowInformationProvider {
|
||||
// JetFlowInformationProvider THROW_EXCEPTION = new JetFlowInformationProvider() {
|
||||
// @Override
|
||||
public class JetFlowInformationProvider {
|
||||
|
||||
private final Map<JetElement, Pseudocode> pseudocodeMap;
|
||||
private BindingTrace trace;
|
||||
|
||||
public JetFlowInformationProvider(@NotNull JetDeclaration declaration, @NotNull final JetExpression bodyExpression, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory, @NotNull BindingTrace trace) {
|
||||
this.trace = trace;
|
||||
final JetPseudocodeTrace pseudocodeTrace = flowDataTraceFactory.createTrace(declaration);
|
||||
pseudocodeMap = new HashMap<JetElement, Pseudocode>();
|
||||
final Map<JetElement, Instruction> representativeInstructions = new HashMap<JetElement, Instruction>();
|
||||
final Map<JetExpression, LoopInfo> loopInfo = Maps.newHashMap();
|
||||
JetPseudocodeTrace wrappedTrace = new JetPseudocodeTrace() {
|
||||
@Override
|
||||
public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) {
|
||||
pseudocodeTrace.recordControlFlowData(element, pseudocode);
|
||||
pseudocodeMap.put(element, pseudocode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction) {
|
||||
Instruction oldValue = representativeInstructions.put(element, instruction);
|
||||
// assert oldValue == null : element.getText();
|
||||
pseudocodeTrace.recordRepresentativeInstruction(element, instruction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordLoopInfo(JetExpression expression, LoopInfo blockInfo) {
|
||||
loopInfo.put(expression, blockInfo);
|
||||
pseudocodeTrace.recordLoopInfo(expression, blockInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
pseudocodeTrace.close();
|
||||
for (Pseudocode pseudocode : pseudocodeMap.values()) {
|
||||
pseudocode.postProcess();
|
||||
}
|
||||
}
|
||||
};
|
||||
JetControlFlowInstructionsGenerator instructionsGenerator = new JetControlFlowInstructionsGenerator(wrappedTrace);
|
||||
new JetControlFlowProcessor(trace, instructionsGenerator).generate(declaration, bodyExpression);
|
||||
wrappedTrace.close();
|
||||
}
|
||||
|
||||
// public void collectReturnedInformation(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions, @NotNull Collection<JetElement> elementsReturningUnit) {
|
||||
// throw new UnsupportedOperationException();
|
||||
// }
|
||||
// Pseudocode pseudocode = pseudocodeMap.get(subroutine);
|
||||
// assert pseudocode != null;
|
||||
//
|
||||
// @Override
|
||||
// public void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions) {
|
||||
// throw new UnsupportedOperationException();
|
||||
// SubroutineExitInstruction exitInstruction = pseudocode.getExitInstruction();
|
||||
// processPreviousInstructions(exitInstruction, new HashSet<Instruction>(), returnedExpressions, elementsReturningUnit);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetElement> unreachableElements) {
|
||||
// throw new UnsupportedOperationException();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
|
||||
public void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull final Collection<JetExpression> returnedExpressions) {
|
||||
Pseudocode pseudocode = pseudocodeMap.get(subroutine);
|
||||
assert pseudocode != null;
|
||||
|
||||
SubroutineExitInstruction exitInstruction = pseudocode.getExitInstruction();
|
||||
for (Instruction previousInstruction : exitInstruction.getPreviousInstructions()) {
|
||||
previousInstruction.accept(new InstructionVisitor() {
|
||||
@Override
|
||||
public void visitReturnValue(ReturnValueInstruction instruction) {
|
||||
returnedExpressions.add((JetExpression) instruction.getElement());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReturnNoValue(ReturnNoValueInstruction instruction) {
|
||||
returnedExpressions.add((JetExpression) instruction.getElement());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void visitJump(AbstractJumpInstruction instruction) {
|
||||
// Nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitUnconditionalJump(UnconditionalJumpInstruction instruction) {
|
||||
for (Instruction previousInstruction : instruction.getPreviousInstructions()) {
|
||||
previousInstruction.accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInstruction(Instruction instruction) {
|
||||
if (instruction instanceof JetElementInstruction) {
|
||||
JetElementInstruction elementInstruction = (JetElementInstruction) instruction;
|
||||
returnedExpressions.add((JetExpression) elementInstruction.getElement());
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException(instruction + " precedes the exit point");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetElement> unreachableElements) {
|
||||
Pseudocode pseudocode = pseudocodeMap.get(subroutine);
|
||||
assert pseudocode != null;
|
||||
|
||||
SubroutineEnterInstruction enterInstruction = pseudocode.getEnterInstruction();
|
||||
Set<Instruction> visited = new HashSet<Instruction>();
|
||||
collectReachable(enterInstruction, visited, null);
|
||||
|
||||
for (Instruction instruction : pseudocode.getInstructions()) {
|
||||
if (!visited.contains(instruction) &&
|
||||
instruction instanceof JetElementInstruction &&
|
||||
// TODO : do {return} while (1 > a)
|
||||
!(instruction instanceof ReadUnitValueInstruction)) {
|
||||
unreachableElements.add(((JetElementInstruction) instruction).getElement());
|
||||
}
|
||||
}
|
||||
}
|
||||
// public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection<JetElement> dominated) {
|
||||
// throw new UnsupportedOperationException();
|
||||
// Instruction dominatorInstruction = representativeInstructions.get(dominator);
|
||||
// if (dominatorInstruction == null) {
|
||||
// return;
|
||||
// }
|
||||
// SubroutineEnterInstruction enterInstruction = dominatorInstruction.getOwner().getEnterInstruction();
|
||||
//
|
||||
// Set<Instruction> reachable = new HashSet<Instruction>();
|
||||
// collectReachable(enterInstruction, reachable, null);
|
||||
//
|
||||
// Set<Instruction> reachableWithDominatorProhibited = new HashSet<Instruction>();
|
||||
// reachableWithDominatorProhibited.add(dominatorInstruction);
|
||||
// collectReachable(enterInstruction, reachableWithDominatorProhibited, null);
|
||||
//
|
||||
// for (Instruction instruction : reachable) {
|
||||
// if (instruction instanceof JetElementInstruction
|
||||
// && reachable.contains(instruction)
|
||||
// && !reachableWithDominatorProhibited.contains(instruction)) {
|
||||
// JetElementInstruction elementInstruction = (JetElementInstruction) instruction;
|
||||
// dominated.add(elementInstruction.getElement());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean isBreakable(JetLoopExpression loop) {
|
||||
// throw new UnsupportedOperationException();
|
||||
// LoopInfo info = loopInfo.get(loop);
|
||||
// Pseudocode.PseudocodeLabel bodyEntryPoint = (Pseudocode.PseudocodeLabel) info.getBodyEntryPoint();
|
||||
// Pseudocode.PseudocodeLabel exitPoint = (Pseudocode.PseudocodeLabel) info.getExitPoint();
|
||||
// HashSet<Instruction> visited = Sets.newHashSet();
|
||||
// Pseudocode.PseudocodeLabel conditionEntryPoint = (Pseudocode.PseudocodeLabel) info.getConditionEntryPoint();
|
||||
// visited.add(conditionEntryPoint.resolveToInstruction());
|
||||
// return collectReachable(bodyEntryPoint.resolveToInstruction(), visited, exitPoint.resolveToInstruction());
|
||||
// }
|
||||
//
|
||||
// };
|
||||
//
|
||||
// JetFlowInformationProvider NONE = new JetFlowInformationProvider() {
|
||||
// @Override
|
||||
// public void collectReturnedInformation(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions, @NotNull Collection<JetElement> elementsReturningUnit) {
|
||||
// public boolean isReachable(JetExpression from, JetExpression to) {
|
||||
// Instruction fromInstr = representativeInstructions.get(from);
|
||||
// assert fromInstr != null : "No representative instruction for " + from.getText();
|
||||
// Instruction toInstr = representativeInstructions.get(to);
|
||||
// assert toInstr != null : "No representative instruction for " + to.getText();
|
||||
//
|
||||
// return collectReachable(fromInstr, Sets.<Instruction>newHashSet(), toInstr);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions) {
|
||||
//
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetElement> unreachableElements) {
|
||||
//
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection<JetElement> dominated) {
|
||||
//
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean isBreakable(JetLoopExpression loop) {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// };
|
||||
// }
|
||||
|
||||
/**
|
||||
* Collects expressions returned from the given subroutine and 'return;' expressions
|
||||
*/
|
||||
void collectReturnedInformation(
|
||||
@NotNull JetElement subroutine,
|
||||
@NotNull Collection<JetExpression> returnedExpressions,
|
||||
@NotNull Collection<JetElement> elementsReturningUnit);
|
||||
private boolean collectReachable(Instruction current, Set<Instruction> visited, @Nullable Instruction lookFor) {
|
||||
if (!visited.add(current)) return false;
|
||||
if (current == lookFor) return true;
|
||||
|
||||
/**
|
||||
* Collects all 'return ...' expressions that return from the given subroutine and all the expressions that precede the exit point
|
||||
*/
|
||||
void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions);
|
||||
for (Instruction nextInstruction : current.getNextInstructions()) {
|
||||
if (collectReachable(nextInstruction, visited, lookFor)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void collectUnreachableExpressions(
|
||||
@NotNull JetElement subroutine,
|
||||
@NotNull Collection<JetElement> unreachableElements);
|
||||
// private void processPreviousInstructions(Instruction previousFor, final Set<Instruction> visited, final Collection<JetExpression> returnedExpressions, final Collection<JetElement> elementsReturningUnit) {
|
||||
// if (!visited.add(previousFor)) return;
|
||||
//
|
||||
// Collection<Instruction> previousInstructions = previousFor.getPreviousInstructions();
|
||||
// InstructionVisitor visitor = new InstructionVisitor() {
|
||||
// @Override
|
||||
// public void visitReadValue(ReadValueInstruction instruction) {
|
||||
// returnedExpressions.add((JetExpression) instruction.getElement());
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void visitReturnValue(ReturnValueInstruction instruction) {
|
||||
// processPreviousInstructions(instruction, visited, returnedExpressions, elementsReturningUnit);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void visitReturnNoValue(ReturnNoValueInstruction instruction) {
|
||||
// elementsReturningUnit.add(instruction.getElement());
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void visitSubroutineEnter(SubroutineEnterInstruction instruction) {
|
||||
// elementsReturningUnit.add(instruction.getSubroutine());
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void visitUnsupportedElementInstruction(UnsupportedElementInstruction instruction) {
|
||||
// context.getTrace().report(UNSUPPORTED.on(instruction.getElement(), "Control-flow builder"));
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void visitWriteValue(WriteValueInstruction writeValueInstruction) {
|
||||
// elementsReturningUnit.add(writeValueInstruction.getElement());
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void visitJump(AbstractJumpInstruction instruction) {
|
||||
// processPreviousInstructions(instruction, visited, returnedExpressions, elementsReturningUnit);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void visitReadUnitValue(ReadUnitValueInstruction instruction) {
|
||||
// returnedExpressions.add((JetExpression) instruction.getElement());
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void visitInstruction(Instruction instruction) {
|
||||
// if (instruction instanceof JetElementInstructionImpl) {
|
||||
// JetElementInstructionImpl elementInstruction = (JetElementInstructionImpl) instruction;
|
||||
// context.getTrace().report(UNSUPPORTED.on(elementInstruction.getElement(), "Control-flow builder"));
|
||||
// }
|
||||
// else {
|
||||
// throw new UnsupportedOperationException(instruction.toString());
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// for (Instruction previousInstruction : previousInstructions) {
|
||||
// previousInstruction.accept(visitor);
|
||||
// }
|
||||
// }
|
||||
|
||||
void collectDominatedExpressions(
|
||||
@NotNull JetExpression dominator,
|
||||
@NotNull Collection<JetElement> dominated);
|
||||
private <D> Map<Instruction, D> traverseInstructionGraphUntilFactsStabilization(Pseudocode pseudocode, InstructionsMergeHandler<D> instructionsMergeHandler, D initialDataValue, boolean straightDirection) {
|
||||
Map<Instruction, D> dataMap = Maps.newHashMap();
|
||||
initializeDataMap(dataMap, pseudocode, initialDataValue);
|
||||
|
||||
boolean isBreakable(JetLoopExpression loop);
|
||||
boolean[] changed = new boolean[1];
|
||||
changed[0] = true;
|
||||
while (changed[0]) {
|
||||
changed[0] = false;
|
||||
traverseSubGraph(pseudocode, instructionsMergeHandler, Collections.<Instruction>emptyList(), straightDirection, dataMap, changed);
|
||||
}
|
||||
return dataMap;
|
||||
}
|
||||
|
||||
private <D> void initializeDataMap(Map<Instruction, D> dataMap, Pseudocode pseudocode, D initialDataValue) {
|
||||
List<Instruction> instructions = pseudocode.getInstructions();
|
||||
for (Instruction instruction : instructions) {
|
||||
dataMap.put(instruction, initialDataValue);
|
||||
if (instruction instanceof LocalDeclarationInstruction) {
|
||||
initializeDataMap(dataMap, ((LocalDeclarationInstruction) instruction).getBody(), initialDataValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private <D> void traverseSubGraph(Pseudocode pseudocode, InstructionsMergeHandler<D> instructionsMergeHandler, Collection<Instruction> previousSubGraphInstructions, boolean straightDirection, Map<Instruction, D> dataMap, boolean[] changed) {
|
||||
List<Instruction> instructions = pseudocode.getInstructions();
|
||||
SubroutineEnterInstruction enterInstruction = pseudocode.getEnterInstruction();
|
||||
for (Instruction instruction : instructions) {
|
||||
Collection<Instruction> allPreviousInstructions;
|
||||
Collection<Instruction> previousInstructions = straightDirection
|
||||
? instruction.getPreviousInstructions()
|
||||
: instruction.getNextInstructions();
|
||||
|
||||
if (instruction == enterInstruction && !previousSubGraphInstructions.isEmpty()) {
|
||||
allPreviousInstructions = Lists.newArrayList(previousInstructions);
|
||||
allPreviousInstructions.addAll(previousSubGraphInstructions);
|
||||
}
|
||||
else {
|
||||
allPreviousInstructions = previousInstructions;
|
||||
}
|
||||
|
||||
if (instruction instanceof LocalDeclarationInstruction) {
|
||||
Pseudocode subroutinePseudocode = ((LocalDeclarationInstruction) instruction).getBody();
|
||||
traverseSubGraph(subroutinePseudocode, instructionsMergeHandler, previousInstructions, straightDirection, dataMap, changed);
|
||||
}
|
||||
D previousDataValue = dataMap.get(instruction);
|
||||
|
||||
Collection<D> incomingEdgesData = Sets.newHashSet();
|
||||
|
||||
for (Instruction previousInstruction : allPreviousInstructions) {
|
||||
incomingEdgesData.add(dataMap.get(previousInstruction));
|
||||
}
|
||||
D mergedData = instructionsMergeHandler.merge(instruction, previousDataValue, incomingEdgesData);
|
||||
if (!mergedData.equals(previousDataValue)) {
|
||||
changed[0] = true;
|
||||
dataMap.put(instruction, mergedData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void markUninitializedVariables(@NotNull JetElement subroutine) {
|
||||
Pseudocode pseudocode = pseudocodeMap.get(subroutine);
|
||||
assert pseudocode != null;
|
||||
|
||||
Collection<Instruction> instructions = pseudocode.getInstructions();
|
||||
InstructionsMergeHandler<Set<LocalVariableDescriptor>> instructionsMergeHandler = new InstructionsMergeHandler<Set<LocalVariableDescriptor>>() {
|
||||
@Override
|
||||
public Set<LocalVariableDescriptor> merge(Instruction instruction, Set<LocalVariableDescriptor> previousDataValue, Collection<Set<LocalVariableDescriptor>> incomingEdgesData) {
|
||||
Set<LocalVariableDescriptor> initializedVariables = Sets.newHashSet();
|
||||
initializedVariables.addAll(previousDataValue);
|
||||
for (Set<LocalVariableDescriptor> edgeDataValue : incomingEdgesData) {
|
||||
initializedVariables.addAll(edgeDataValue);
|
||||
}
|
||||
|
||||
if (instruction instanceof WriteValueInstruction) {
|
||||
DeclarationDescriptor descriptor = null;
|
||||
JetElement lValue = ((WriteValueInstruction) instruction).getlValue();
|
||||
if (lValue instanceof JetProperty) {
|
||||
descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, lValue);
|
||||
}
|
||||
else if (lValue instanceof JetSimpleNameExpression) {
|
||||
descriptor = trace.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) lValue);
|
||||
}
|
||||
else if (lValue instanceof JetParameter) {
|
||||
descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, lValue);
|
||||
}
|
||||
if (descriptor instanceof LocalVariableDescriptor) {
|
||||
initializedVariables.add((LocalVariableDescriptor) descriptor);
|
||||
}
|
||||
}
|
||||
return initializedVariables;
|
||||
}
|
||||
};
|
||||
Map<Instruction, Set<LocalVariableDescriptor>> dataMap = traverseInstructionGraphUntilFactsStabilization(pseudocode, instructionsMergeHandler, Collections.<LocalVariableDescriptor>emptySet(), true);
|
||||
InstructionDataAnalyzer instructionDataAnalyzer = new InstructionDataAnalyzer<Set<LocalVariableDescriptor>>() {
|
||||
@Override
|
||||
public void analyze(Instruction instruction, Map<Instruction, Set<LocalVariableDescriptor>> dataMap) {
|
||||
Set<LocalVariableDescriptor> initializedVariables = dataMap.get(instruction);
|
||||
if (instruction instanceof ReadValueInstruction) {
|
||||
JetElement element = ((ReadValueInstruction) instruction).getElement();
|
||||
if (element instanceof JetSimpleNameExpression) {
|
||||
DeclarationDescriptor descriptor = trace.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) element);
|
||||
if (descriptor instanceof LocalVariableDescriptor) {
|
||||
if (!initializedVariables.contains(descriptor)) {
|
||||
trace.report(Errors.UNINITIALIZED_VARIABLE.on((JetSimpleNameExpression) element, descriptor));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (instruction instanceof WriteValueInstruction) {
|
||||
JetElement element = ((WriteValueInstruction) instruction).getElement();
|
||||
if (element instanceof JetSimpleNameExpression) {
|
||||
DeclarationDescriptor descriptor = trace.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) element);
|
||||
if (descriptor instanceof LocalVariableDescriptor) {
|
||||
if (initializedVariables.contains(descriptor) && ((LocalVariableDescriptor) descriptor).isVar()) {
|
||||
trace.report(Errors.VAL_REASSIGNMENT.on((JetSimpleNameExpression) element, descriptor));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
traverseInstructionGraphAndReportErrors(instructions, dataMap, instructionDataAnalyzer);
|
||||
}
|
||||
|
||||
private void traverseInstructionGraphAndReportErrors(Collection<Instruction> instructions, Map<Instruction, Set<LocalVariableDescriptor>> dataMap, InstructionDataAnalyzer<Set<LocalVariableDescriptor>> instructionDataAnalyzer) {
|
||||
for (Instruction instruction : instructions) {
|
||||
if (instruction instanceof LocalDeclarationInstruction) {
|
||||
traverseInstructionGraphAndReportErrors(((LocalDeclarationInstruction) instruction).getBody().getInstructions(), dataMap, instructionDataAnalyzer);
|
||||
}
|
||||
instructionDataAnalyzer.analyze(instruction, dataMap);
|
||||
}
|
||||
}
|
||||
|
||||
interface InstructionsMergeHandler<D> {
|
||||
D merge(Instruction instruction, D previousDataValue, Collection<D> incomingEdgesData);
|
||||
}
|
||||
|
||||
interface InstructionDataAnalyzer<D> {
|
||||
void analyze(Instruction instruction, Map<Instruction, D> dataMap);
|
||||
}
|
||||
}
|
||||
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class FunctionLiteralValueInstruction extends ReadValueInstruction {
|
||||
|
||||
private Pseudocode body;
|
||||
|
||||
public FunctionLiteralValueInstruction(@NotNull JetFunctionLiteralExpression expression) {
|
||||
super(expression);
|
||||
}
|
||||
|
||||
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() + ")";
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ public interface Instruction {
|
||||
|
||||
void setOwner(@NotNull Pseudocode owner);
|
||||
|
||||
@NotNull
|
||||
Collection<Instruction> getPreviousInstructions();
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -28,6 +28,7 @@ public abstract class InstructionImpl implements Instruction {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<Instruction> getPreviousInstructions() {
|
||||
return previousInstructions;
|
||||
|
||||
@@ -8,7 +8,7 @@ public class InstructionVisitor {
|
||||
visitInstructionWithNext(instruction);
|
||||
}
|
||||
|
||||
public void visitFunctionLiteralValue(FunctionLiteralValueInstruction instruction) {
|
||||
public void visitFunctionLiteralValue(LocalDeclarationInstruction instruction) {
|
||||
visitReadValue(instruction);
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ public class InstructionVisitor {
|
||||
}
|
||||
|
||||
public void visitNondeterministicJump(NondeterministicJumpInstruction instruction) {
|
||||
visitJump(instruction);
|
||||
visitInstruction(instruction);
|
||||
}
|
||||
|
||||
public void visitUnsupportedElementInstruction(UnsupportedElementInstruction instruction) {
|
||||
|
||||
+21
-15
@@ -2,10 +2,7 @@ package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.cfg.*;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetThrowExpression;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -25,7 +22,6 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
||||
private final JetPseudocodeTrace trace;
|
||||
|
||||
public JetControlFlowInstructionsGenerator(JetPseudocodeTrace trace) {
|
||||
super(null);
|
||||
this.trace = trace;
|
||||
}
|
||||
|
||||
@@ -41,28 +37,31 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
||||
if (!builders.isEmpty()) {
|
||||
builder = builders.peek();
|
||||
}
|
||||
else {
|
||||
builder = null;
|
||||
}
|
||||
return worker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterSubroutine(@NotNull JetElement subroutine, boolean isFunctionLiteral) {
|
||||
if (isFunctionLiteral) {
|
||||
public void enterSubroutine(@NotNull JetDeclaration subroutine) {
|
||||
if (builder != null) {
|
||||
pushBuilder(subroutine, builder.getCurrentSubroutine());
|
||||
}
|
||||
else {
|
||||
pushBuilder(subroutine, subroutine);
|
||||
}
|
||||
builder.enterSubroutine(subroutine, false);
|
||||
assert builder != null;
|
||||
builder.enterSubroutine(subroutine);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitSubroutine(@NotNull JetElement subroutine, boolean functionLiteral) {
|
||||
super.exitSubroutine(subroutine, functionLiteral);
|
||||
public void exitSubroutine(@NotNull JetDeclaration subroutine) {
|
||||
super.exitSubroutine(subroutine);
|
||||
JetControlFlowInstructionsGeneratorWorker worker = popBuilder(subroutine);
|
||||
if (functionLiteral) {
|
||||
if (!builders.empty()) {
|
||||
JetControlFlowInstructionsGeneratorWorker builder = builders.peek();
|
||||
FunctionLiteralValueInstruction instruction = new FunctionLiteralValueInstruction((JetFunctionLiteralExpression) subroutine);
|
||||
instruction.setBody(worker.getPseudocode());
|
||||
LocalDeclarationInstruction instruction = new LocalDeclarationInstruction(subroutine, worker.getPseudocode());
|
||||
builder.add(instruction);
|
||||
}
|
||||
}
|
||||
@@ -128,7 +127,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterSubroutine(@NotNull JetElement subroutine, boolean isFunctionLiteral) {
|
||||
public void enterSubroutine(@NotNull JetDeclaration subroutine) {
|
||||
Label entryPoint = createUnboundLabel();
|
||||
BreakableBlockInfo blockInfo = new BreakableBlockInfo(subroutine, entryPoint, createUnboundLabel());
|
||||
// subroutineInfo.push(blockInfo);
|
||||
@@ -179,7 +178,7 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitSubroutine(@NotNull JetElement subroutine, boolean functionLiteral) {
|
||||
public void exitSubroutine(@NotNull JetDeclaration subroutine) {
|
||||
bindLabel(getExitPoint(subroutine));
|
||||
pseudocode.addExitInstruction(new SubroutineExitInstruction(subroutine, "<END>"));
|
||||
bindLabel(error);
|
||||
@@ -246,6 +245,13 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
|
||||
add(new NondeterministicJumpInstruction(label));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nondeterministicJump(List<Label> labels) {
|
||||
//todo
|
||||
//handleJumpInsideTryFinally(label);
|
||||
add(new NondeterministicJumpInstruction(labels));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jumpToError(JetThrowExpression expression) {
|
||||
add(new UnconditionalJumpInstruction(error));
|
||||
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetClass;
|
||||
import org.jetbrains.jet.lang.psi.JetDeclaration;
|
||||
import org.jetbrains.jet.lang.psi.JetFunction;
|
||||
import org.jetbrains.jet.lang.psi.JetObjectDeclaration;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public class LocalDeclarationInstruction extends ReadValueInstruction {
|
||||
|
||||
private Pseudocode body;
|
||||
|
||||
public LocalDeclarationInstruction(@NotNull JetDeclaration element, Pseudocode body) {
|
||||
super(element);
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public Pseudocode getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(InstructionVisitor visitor) {
|
||||
visitor.visitFunctionLiteralValue(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String kind = "!";
|
||||
if (element instanceof JetFunction) {
|
||||
kind = "f";
|
||||
}
|
||||
else if (element instanceof JetClass) {
|
||||
kind = "c";
|
||||
}
|
||||
else if (element instanceof JetObjectDeclaration) {
|
||||
kind = "o";
|
||||
}
|
||||
return "r" + kind + "(" + element.getText() + ")";
|
||||
}
|
||||
}
|
||||
+47
-15
@@ -1,20 +1,48 @@
|
||||
package org.jetbrains.jet.lang.cfg.pseudocode;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.cfg.Label;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
* @author svtk
|
||||
*/
|
||||
public class NondeterministicJumpInstruction extends AbstractJumpInstruction {
|
||||
|
||||
public class NondeterministicJumpInstruction extends InstructionImpl{
|
||||
private Instruction next;
|
||||
private final List<Label> targetLabels;
|
||||
private final Map<Label, Instruction> resolvedTargets;
|
||||
|
||||
public NondeterministicJumpInstruction(List<Label> targetLabels) {
|
||||
this.targetLabels = targetLabels;
|
||||
resolvedTargets = Maps.newLinkedHashMap();
|
||||
}
|
||||
|
||||
public NondeterministicJumpInstruction(Label targetLabel) {
|
||||
super(targetLabel);
|
||||
this(Lists.newArrayList(targetLabel));
|
||||
}
|
||||
|
||||
public List<Label> getTargetLabels() {
|
||||
return targetLabels;
|
||||
}
|
||||
|
||||
public Map<Label, Instruction> getResolvedTargets() {
|
||||
return resolvedTargets;
|
||||
}
|
||||
|
||||
public void setResolvedTarget(Label label, Instruction resolvedTarget) {
|
||||
Instruction target = outgoingEdgeTo(resolvedTarget);
|
||||
resolvedTargets.put(label, target);
|
||||
}
|
||||
|
||||
public Instruction getNext() {
|
||||
return next;
|
||||
}
|
||||
public void setNext(Instruction next) {
|
||||
this.next = outgoingEdgeTo(next);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -22,22 +50,26 @@ public class NondeterministicJumpInstruction extends AbstractJumpInstruction {
|
||||
visitor.visitNondeterministicJump(this);
|
||||
}
|
||||
|
||||
public Instruction getNext() {
|
||||
return next;
|
||||
}
|
||||
|
||||
public void setNext(Instruction next) {
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<Instruction> getNextInstructions() {
|
||||
return Arrays.asList(getResolvedTarget(), getNext());
|
||||
ArrayList<Instruction> targetInstructions = Lists.newArrayList(getResolvedTargets().values());
|
||||
targetInstructions.add(getNext());
|
||||
return targetInstructions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "jmp?(" + getTargetLabel().getName() + ")";
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("jmp?(");
|
||||
for (Iterator<Label> iterator = targetLabels.iterator(); iterator.hasNext(); ) {
|
||||
Label targetLabel = iterator.next();
|
||||
sb.append(targetLabel.getName());
|
||||
if (iterator.hasNext()) {
|
||||
sb.append(", ");
|
||||
}
|
||||
}
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.cfg.Label;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
@@ -75,10 +74,15 @@ public class Pseudocode {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Collection<Instruction> getInstructions() {
|
||||
public List<Instruction> getInstructions() {
|
||||
return instructions;
|
||||
}
|
||||
|
||||
@Deprecated //for tests only
|
||||
public List<PseudocodeLabel> getLabels() {
|
||||
return labels;
|
||||
}
|
||||
|
||||
public void addExitInstruction(SubroutineExitInstruction exitInstruction) {
|
||||
addInstruction(exitInstruction);
|
||||
assert this.exitInstruction == null;
|
||||
@@ -124,7 +128,10 @@ public class Pseudocode {
|
||||
@Override
|
||||
public void visitNondeterministicJump(NondeterministicJumpInstruction instruction) {
|
||||
instruction.setNext(getNextPosition(currentPosition));
|
||||
visitJump(instruction);
|
||||
List<Label> targetLabels = instruction.getTargetLabels();
|
||||
for (Label targetLabel : targetLabels) {
|
||||
instruction.setResolvedTarget(targetLabel, getJumpTarget(targetLabel));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -143,7 +150,7 @@ public class Pseudocode {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFunctionLiteralValue(FunctionLiteralValueInstruction instruction) {
|
||||
public void visitFunctionLiteralValue(LocalDeclarationInstruction instruction) {
|
||||
instruction.getBody().postProcess();
|
||||
super.visitFunctionLiteralValue(instruction);
|
||||
}
|
||||
@@ -163,170 +170,30 @@ public class Pseudocode {
|
||||
|
||||
@NotNull
|
||||
private Instruction getJumpTarget(@NotNull Label targetLabel) {
|
||||
return getTargetInstruction(((PseudocodeLabel) targetLabel).resolve());
|
||||
return ((PseudocodeLabel)targetLabel).resolveToInstruction();
|
||||
//return getTargetInstruction(((PseudocodeLabel) targetLabel).resolve());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Instruction getTargetInstruction(@NotNull List<Instruction> instructions) {
|
||||
while (true) {
|
||||
assert instructions != null;
|
||||
Instruction targetInstruction = instructions.get(0);
|
||||
|
||||
if (false == targetInstruction instanceof UnconditionalJumpInstruction) {
|
||||
return targetInstruction;
|
||||
}
|
||||
|
||||
Label label = ((UnconditionalJumpInstruction) targetInstruction).getTargetLabel();
|
||||
instructions = ((PseudocodeLabel)label).resolve();
|
||||
}
|
||||
}
|
||||
// @NotNull
|
||||
// private Instruction getTargetInstruction(@NotNull List<Instruction> instructions) {
|
||||
// while (true) {
|
||||
// assert instructions != null;
|
||||
// Instruction targetInstruction = instructions.get(0);
|
||||
//
|
||||
// //if (false == targetInstruction instanceof UnconditionalJumpInstruction) {
|
||||
// return targetInstruction;
|
||||
// //}
|
||||
//
|
||||
//// Label label = ((UnconditionalJumpInstruction) targetInstruction).getTargetLabel();
|
||||
//// instructions = ((PseudocodeLabel)label).resolve();
|
||||
// }
|
||||
// }
|
||||
|
||||
@NotNull
|
||||
private Instruction getNextPosition(int currentPosition) {
|
||||
int targetPosition = currentPosition + 1;
|
||||
assert targetPosition < instructions.size() : currentPosition;
|
||||
return getTargetInstruction(instructions.subList(targetPosition, instructions.size()));
|
||||
return instructions.get(targetPosition);
|
||||
//return getTargetInstruction(instructions.subList(targetPosition, instructions.size()));
|
||||
}
|
||||
|
||||
public void dfsDump(StringBuilder nodes, StringBuilder edges, Map<Instruction, String> nodeNames) {
|
||||
dfsDump(nodes, edges, instructions.get(0), nodeNames);
|
||||
}
|
||||
|
||||
private void dfsDump(StringBuilder nodes, StringBuilder edges, Instruction instruction, Map<Instruction, String> nodeNames) {
|
||||
if (nodeNames.containsKey(instruction)) return;
|
||||
String name = "n" + nodeNames.size();
|
||||
nodeNames.put(instruction, name);
|
||||
nodes.append(name).append(" := ").append(renderName(instruction));
|
||||
|
||||
}
|
||||
|
||||
private String renderName(Instruction instruction) {
|
||||
throw new UnsupportedOperationException(); // TODO
|
||||
}
|
||||
|
||||
public void dumpInstructions(@NotNull StringBuilder out) {
|
||||
List<Pseudocode> locals = new ArrayList<Pseudocode>();
|
||||
for (int i = 0, instructionsSize = instructions.size(); i < instructionsSize; i++) {
|
||||
Instruction instruction = instructions.get(i);
|
||||
if (instruction instanceof FunctionLiteralValueInstruction) {
|
||||
FunctionLiteralValueInstruction functionLiteralValueInstruction = (FunctionLiteralValueInstruction) instruction;
|
||||
locals.add(functionLiteralValueInstruction.getBody());
|
||||
}
|
||||
for (PseudocodeLabel label: labels) {
|
||||
if (label.getTargetInstructionIndex() == i) {
|
||||
out.append(label.getName()).append(":\n");
|
||||
}
|
||||
}
|
||||
out.append(" ").append(instruction).append("\n");
|
||||
}
|
||||
for (Pseudocode local : locals) {
|
||||
local.dumpInstructions(out);
|
||||
}
|
||||
}
|
||||
|
||||
public void dumpEdges(final PrintStream out, final int[] count, final Map<Instruction, String> nodeToName) {
|
||||
for (final Instruction fromInst : instructions) {
|
||||
fromInst.accept(new InstructionVisitor() {
|
||||
@Override
|
||||
public void visitFunctionLiteralValue(FunctionLiteralValueInstruction instruction) {
|
||||
int index = count[0];
|
||||
// instruction.getBody().dumpSubgraph(out, "subgraph cluster_" + index, count, "color=blue;\nlabel = \"f" + index + "\";", nodeToName);
|
||||
printEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getBody().instructions.get(0)), null);
|
||||
visitInstructionWithNext(instruction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitUnconditionalJump(UnconditionalJumpInstruction instruction) {
|
||||
// Nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJump(AbstractJumpInstruction instruction) {
|
||||
printEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getResolvedTarget()), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNondeterministicJump(NondeterministicJumpInstruction instruction) {
|
||||
visitJump(instruction);
|
||||
printEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getNext()), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReturnValue(ReturnValueInstruction instruction) {
|
||||
super.visitReturnValue(instruction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReturnNoValue(ReturnNoValueInstruction instruction) {
|
||||
super.visitReturnNoValue(instruction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitConditionalJump(ConditionalJumpInstruction instruction) {
|
||||
String from = nodeToName.get(instruction);
|
||||
printEdge(out, from, nodeToName.get(instruction.getNextOnFalse()), "no");
|
||||
printEdge(out, from, nodeToName.get(instruction.getNextOnTrue()), "yes");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInstructionWithNext(InstructionWithNext instruction) {
|
||||
printEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getNext()), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSubroutineExit(SubroutineExitInstruction instruction) {
|
||||
// Nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInstruction(Instruction instruction) {
|
||||
throw new UnsupportedOperationException(instruction.toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void dumpNodes(PrintStream out, int[] count, Map<Instruction, String> nodeToName) {
|
||||
for (Instruction node : instructions) {
|
||||
if (node instanceof UnconditionalJumpInstruction) {
|
||||
continue;
|
||||
}
|
||||
String name = "n" + count[0]++;
|
||||
nodeToName.put(node, name);
|
||||
String text = node.toString();
|
||||
int newline = text.indexOf("\n");
|
||||
if (newline >= 0) {
|
||||
text = text.substring(0, newline);
|
||||
}
|
||||
String shape = "box";
|
||||
if (node instanceof ConditionalJumpInstruction) {
|
||||
shape = "diamond";
|
||||
}
|
||||
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";
|
||||
}
|
||||
else if (node instanceof SubroutineEnterInstruction || node instanceof SubroutineExitInstruction) {
|
||||
shape = "roundrect, style=rounded";
|
||||
}
|
||||
out.println(name + "[label=\"" + text + "\", shape=" + shape + "];");
|
||||
}
|
||||
}
|
||||
|
||||
private void printEdge(PrintStream out, String from, String to, String label) {
|
||||
if (label != null) {
|
||||
label = "[label=\"" + label + "\"]";
|
||||
}
|
||||
else {
|
||||
label = "";
|
||||
}
|
||||
out.println(from + " -> " + to + label + ";");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,11 @@ public class WriteValueInstruction extends InstructionWithNext {
|
||||
this.lValue = lValue;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JetElement getlValue() {
|
||||
return lValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(InstructionVisitor visitor) {
|
||||
visitor.visitWriteValue(this);
|
||||
|
||||
@@ -142,6 +142,9 @@ public interface Errors {
|
||||
};
|
||||
PsiElementOnlyDiagnosticFactory3<JetModifierListOwner, CallableMemberDescriptor, CallableMemberDescriptor, DeclarationDescriptor> VIRTUAL_MEMBER_HIDDEN = PsiElementOnlyDiagnosticFactory3.create(ERROR, "''{0}'' hides ''{1}'' in class {2} and needs 'override' modifier", DescriptorRenderer.TEXT);
|
||||
|
||||
PsiElementOnlyDiagnosticFactory1<JetSimpleNameExpression, DeclarationDescriptor> UNINITIALIZED_VARIABLE = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Variable ''{0}'' must be uninitialized", NAME);
|
||||
PsiElementOnlyDiagnosticFactory1<JetSimpleNameExpression, DeclarationDescriptor> VAL_REASSIGNMENT = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Val can not be reassigned", NAME);
|
||||
|
||||
SimpleDiagnosticFactory UNREACHABLE_CODE = SimpleDiagnosticFactory.create(ERROR, "Unreachable code");
|
||||
|
||||
SimpleDiagnosticFactory MANY_CLASS_OBJECTS = SimpleDiagnosticFactory.create(ERROR, "Only one class object is allowed per class");
|
||||
|
||||
@@ -74,7 +74,7 @@ public class AnalyzingUtils {
|
||||
|
||||
public BindingContext analyzeNamespaces(@NotNull Project project, @NotNull List<? extends JetDeclaration> declarations, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) {
|
||||
BindingTraceContext bindingTraceContext = new BindingTraceContext();
|
||||
JetSemanticServices semanticServices = JetSemanticServices.createSemanticServices(project, flowDataTraceFactory);
|
||||
JetSemanticServices semanticServices = JetSemanticServices.createSemanticServices(project);
|
||||
|
||||
JetScope libraryScope = semanticServices.getStandardLibrary().getLibraryScope();
|
||||
ModuleDescriptor owner = new ModuleDescriptor("<module>");
|
||||
@@ -111,7 +111,7 @@ public class AnalyzingUtils {
|
||||
public ClassObjectStatus setClassObjectDescriptor(@NotNull MutableClassDescriptor classObjectDescriptor) {
|
||||
throw new IllegalStateException("Must be guaranteed not to happen by the parser");
|
||||
}
|
||||
}, declarations);
|
||||
}, declarations, flowDataTraceFactory);
|
||||
return bindingTraceContext.getBindingContext();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,17 +2,12 @@ package org.jetbrains.jet.lang.resolve;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.JetSemanticServices;
|
||||
import org.jetbrains.jet.lang.cfg.JetControlFlowProcessor;
|
||||
import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider;
|
||||
import org.jetbrains.jet.lang.cfg.LoopInfo;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.*;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||
import org.jetbrains.jet.lang.diagnostics.Errors;
|
||||
@@ -37,15 +32,13 @@ public class ClassDescriptorResolver {
|
||||
private final TypeResolver typeResolver;
|
||||
private final TypeResolver typeResolverNotCheckingBounds;
|
||||
private final BindingTrace trace;
|
||||
private final JetControlFlowDataTraceFactory flowDataTraceFactory;
|
||||
private final AnnotationResolver annotationResolver;
|
||||
|
||||
public ClassDescriptorResolver(JetSemanticServices semanticServices, BindingTrace trace, JetControlFlowDataTraceFactory flowDataTraceFactory) {
|
||||
public ClassDescriptorResolver(JetSemanticServices semanticServices, BindingTrace trace) {
|
||||
this.semanticServices = semanticServices;
|
||||
this.typeResolver = new TypeResolver(semanticServices, trace, true);
|
||||
this.typeResolverNotCheckingBounds = new TypeResolver(semanticServices, trace, false);
|
||||
this.trace = trace;
|
||||
this.flowDataTraceFactory = flowDataTraceFactory;
|
||||
this.annotationResolver = new AnnotationResolver(semanticServices, trace);
|
||||
}
|
||||
|
||||
@@ -815,230 +808,4 @@ public class ClassDescriptorResolver {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public JetFlowInformationProvider computeFlowData(@NotNull JetElement declaration, @NotNull final JetExpression bodyExpression) {
|
||||
final JetPseudocodeTrace pseudocodeTrace = flowDataTraceFactory.createTrace(declaration);
|
||||
final Map<JetElement, Pseudocode> pseudocodeMap = new HashMap<JetElement, Pseudocode>();
|
||||
final Map<JetElement, Instruction> representativeInstructions = new HashMap<JetElement, Instruction>();
|
||||
final Map<JetExpression, LoopInfo> loopInfo = Maps.newHashMap();
|
||||
JetPseudocodeTrace wrappedTrace = new JetPseudocodeTrace() {
|
||||
@Override
|
||||
public void recordControlFlowData(@NotNull JetElement element, @NotNull Pseudocode pseudocode) {
|
||||
pseudocodeTrace.recordControlFlowData(element, pseudocode);
|
||||
pseudocodeMap.put(element, pseudocode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordRepresentativeInstruction(@NotNull JetElement element, @NotNull Instruction instruction) {
|
||||
Instruction oldValue = representativeInstructions.put(element, instruction);
|
||||
// assert oldValue == null : element.getText();
|
||||
pseudocodeTrace.recordRepresentativeInstruction(element, instruction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordLoopInfo(JetExpression expression, LoopInfo blockInfo) {
|
||||
loopInfo.put(expression, blockInfo);
|
||||
pseudocodeTrace.recordLoopInfo(expression, blockInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
pseudocodeTrace.close();
|
||||
for (Pseudocode pseudocode : pseudocodeMap.values()) {
|
||||
pseudocode.postProcess();
|
||||
}
|
||||
}
|
||||
};
|
||||
JetControlFlowInstructionsGenerator instructionsGenerator = new JetControlFlowInstructionsGenerator(wrappedTrace);
|
||||
new JetControlFlowProcessor(trace, instructionsGenerator).generate(declaration, bodyExpression);
|
||||
wrappedTrace.close();
|
||||
return new JetFlowInformationProvider() {
|
||||
@Override
|
||||
public void collectReturnedInformation(@NotNull JetElement subroutine, @NotNull Collection<JetExpression> returnedExpressions, @NotNull Collection<JetElement> elementsReturningUnit) {
|
||||
Pseudocode pseudocode = pseudocodeMap.get(subroutine);
|
||||
assert pseudocode != null;
|
||||
|
||||
SubroutineExitInstruction exitInstruction = pseudocode.getExitInstruction();
|
||||
processPreviousInstructions(exitInstruction, new HashSet<Instruction>(), returnedExpressions, elementsReturningUnit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collectReturnExpressions(@NotNull JetElement subroutine, @NotNull final Collection<JetExpression> returnedExpressions) {
|
||||
Pseudocode pseudocode = pseudocodeMap.get(subroutine);
|
||||
assert pseudocode != null;
|
||||
|
||||
SubroutineExitInstruction exitInstruction = pseudocode.getExitInstruction();
|
||||
for (Instruction previousInstruction : exitInstruction.getPreviousInstructions()) {
|
||||
previousInstruction.accept(new InstructionVisitor() {
|
||||
@Override
|
||||
public void visitReturnValue(ReturnValueInstruction instruction) {
|
||||
returnedExpressions.add((JetExpression) instruction.getElement());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReturnNoValue(ReturnNoValueInstruction instruction) {
|
||||
returnedExpressions.add((JetExpression) instruction.getElement());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void visitJump(AbstractJumpInstruction instruction) {
|
||||
// Nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInstruction(Instruction instruction) {
|
||||
if (instruction instanceof JetElementInstruction) {
|
||||
JetElementInstruction elementInstruction = (JetElementInstruction) instruction;
|
||||
returnedExpressions.add((JetExpression) elementInstruction.getElement());
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException(instruction + " precedes the exit point");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collectUnreachableExpressions(@NotNull JetElement subroutine, @NotNull Collection<JetElement> unreachableElements) {
|
||||
Pseudocode pseudocode = pseudocodeMap.get(subroutine);
|
||||
assert pseudocode != null;
|
||||
|
||||
SubroutineEnterInstruction enterInstruction = pseudocode.getEnterInstruction();
|
||||
Set<Instruction> visited = new HashSet<Instruction>();
|
||||
collectReachable(enterInstruction, visited, null);
|
||||
|
||||
for (Instruction instruction : pseudocode.getInstructions()) {
|
||||
if (!visited.contains(instruction) &&
|
||||
instruction instanceof JetElementInstruction &&
|
||||
// TODO : do {return} while (1 > a)
|
||||
!(instruction instanceof ReadUnitValueInstruction)) {
|
||||
unreachableElements.add(((JetElementInstruction) instruction).getElement());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collectDominatedExpressions(@NotNull JetExpression dominator, @NotNull Collection<JetElement> dominated) {
|
||||
Instruction dominatorInstruction = representativeInstructions.get(dominator);
|
||||
if (dominatorInstruction == null) {
|
||||
return;
|
||||
}
|
||||
SubroutineEnterInstruction enterInstruction = dominatorInstruction.getOwner().getEnterInstruction();
|
||||
|
||||
Set<Instruction> reachable = new HashSet<Instruction>();
|
||||
collectReachable(enterInstruction, reachable, null);
|
||||
|
||||
Set<Instruction> reachableWithDominatorProhibited = new HashSet<Instruction>();
|
||||
reachableWithDominatorProhibited.add(dominatorInstruction);
|
||||
collectReachable(enterInstruction, reachableWithDominatorProhibited, null);
|
||||
|
||||
for (Instruction instruction : reachable) {
|
||||
if (instruction instanceof JetElementInstruction
|
||||
&& reachable.contains(instruction)
|
||||
&& !reachableWithDominatorProhibited.contains(instruction)) {
|
||||
JetElementInstruction elementInstruction = (JetElementInstruction) instruction;
|
||||
dominated.add(elementInstruction.getElement());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBreakable(JetLoopExpression loop) {
|
||||
LoopInfo info = loopInfo.get(loop);
|
||||
Pseudocode.PseudocodeLabel bodyEntryPoint = (Pseudocode.PseudocodeLabel) info.getBodyEntryPoint();
|
||||
Pseudocode.PseudocodeLabel exitPoint = (Pseudocode.PseudocodeLabel) info.getExitPoint();
|
||||
HashSet<Instruction> visited = Sets.newHashSet();
|
||||
Pseudocode.PseudocodeLabel conditionEntryPoint = (Pseudocode.PseudocodeLabel) info.getConditionEntryPoint();
|
||||
visited.add(conditionEntryPoint.resolveToInstruction());
|
||||
return collectReachable(bodyEntryPoint.resolveToInstruction(), visited, exitPoint.resolveToInstruction());
|
||||
}
|
||||
|
||||
public boolean isReachable(JetExpression from, JetExpression to) {
|
||||
Instruction fromInstr = representativeInstructions.get(from);
|
||||
assert fromInstr != null : "No representative instruction for " + from.getText();
|
||||
Instruction toInstr = representativeInstructions.get(to);
|
||||
assert toInstr != null : "No representative instruction for " + to.getText();
|
||||
|
||||
return collectReachable(fromInstr, Sets.<Instruction>newHashSet(), toInstr);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private boolean collectReachable(Instruction current, Set<Instruction> visited, @Nullable Instruction lookFor) {
|
||||
if (!visited.add(current)) return false;
|
||||
if (current == lookFor) return true;
|
||||
|
||||
for (Instruction nextInstruction : current.getNextInstructions()) {
|
||||
if (collectReachable(nextInstruction, visited, lookFor)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void processPreviousInstructions(Instruction previousFor, final Set<Instruction> visited, final Collection<JetExpression> returnedExpressions, final Collection<JetElement> elementsReturningUnit) {
|
||||
if (!visited.add(previousFor)) return;
|
||||
|
||||
Collection<Instruction> previousInstructions = previousFor.getPreviousInstructions();
|
||||
InstructionVisitor visitor = new InstructionVisitor() {
|
||||
@Override
|
||||
public void visitReadValue(ReadValueInstruction instruction) {
|
||||
returnedExpressions.add((JetExpression) instruction.getElement());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReturnValue(ReturnValueInstruction instruction) {
|
||||
processPreviousInstructions(instruction, visited, returnedExpressions, elementsReturningUnit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReturnNoValue(ReturnNoValueInstruction instruction) {
|
||||
elementsReturningUnit.add(instruction.getElement());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSubroutineEnter(SubroutineEnterInstruction instruction) {
|
||||
elementsReturningUnit.add(instruction.getSubroutine());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitUnsupportedElementInstruction(UnsupportedElementInstruction instruction) {
|
||||
// trace.getErrorHandler().genericError(instruction.getElement().getNode(), "Unsupported by control-flow builder " + instruction.getElement());
|
||||
trace.report(UNSUPPORTED.on(instruction.getElement(), "Control-flow builder"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitWriteValue(WriteValueInstruction writeValueInstruction) {
|
||||
elementsReturningUnit.add(writeValueInstruction.getElement());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJump(AbstractJumpInstruction instruction) {
|
||||
processPreviousInstructions(instruction, visited, returnedExpressions, elementsReturningUnit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReadUnitValue(ReadUnitValueInstruction instruction) {
|
||||
returnedExpressions.add((JetExpression) instruction.getElement());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInstruction(Instruction instruction) {
|
||||
if (instruction instanceof JetElementInstructionImpl) {
|
||||
JetElementInstructionImpl elementInstruction = (JetElementInstructionImpl) instruction;
|
||||
// trace.getErrorHandler().genericError(elementInstruction.getElement().getNode(), "Unsupported by control-flow builder " + elementInstruction.getElement());
|
||||
trace.report(UNSUPPORTED.on(elementInstruction.getElement(), "Control-flow builder"));
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException(instruction.toString());
|
||||
}
|
||||
}
|
||||
};
|
||||
for (Instruction previousInstruction : previousInstructions) {
|
||||
previousInstruction.accept(visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.jetbrains.jet.lang.resolve;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
|
||||
import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptorImpl;
|
||||
@@ -24,11 +25,15 @@ import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
|
||||
*/
|
||||
public class ControlFlowAnalyzer {
|
||||
private TopDownAnalysisContext context;
|
||||
private ExpressionTypingServices typeInferrer;
|
||||
private ExpressionTypingServices typeInferrerServices;
|
||||
private final JetControlFlowDataTraceFactory flowDataTraceFactory;
|
||||
private final boolean declaredLocally;
|
||||
|
||||
public ControlFlowAnalyzer(TopDownAnalysisContext context) {
|
||||
public ControlFlowAnalyzer(TopDownAnalysisContext context, JetControlFlowDataTraceFactory flowDataTraceFactory, boolean declaredLocally) {
|
||||
this.context = context;
|
||||
typeInferrer = context.getSemanticServices().getTypeInferrerServices(context.getTrace());
|
||||
this.flowDataTraceFactory = flowDataTraceFactory;
|
||||
this.typeInferrerServices = context.getSemanticServices().getTypeInferrerServices(context.getTrace());
|
||||
this.declaredLocally = declaredLocally;
|
||||
}
|
||||
|
||||
public void process() {
|
||||
@@ -36,7 +41,9 @@ public class ControlFlowAnalyzer {
|
||||
JetNamedFunction function = entry.getKey();
|
||||
FunctionDescriptorImpl functionDescriptor = entry.getValue();
|
||||
|
||||
final JetType expectedReturnType = !function.hasBlockBody() && !function.hasDeclaredReturnType() ? NO_EXPECTED_TYPE : functionDescriptor.getReturnType();
|
||||
final JetType expectedReturnType = !function.hasBlockBody() && !function.hasDeclaredReturnType()
|
||||
? NO_EXPECTED_TYPE
|
||||
: functionDescriptor.getReturnType();
|
||||
checkFunction(function, functionDescriptor, expectedReturnType);
|
||||
}
|
||||
|
||||
@@ -55,9 +62,11 @@ public class ControlFlowAnalyzer {
|
||||
}
|
||||
|
||||
private void checkFunction(JetDeclarationWithBody function, FunctionDescriptor functionDescriptor, final @NotNull JetType expectedReturnType) {
|
||||
assert function instanceof JetDeclaration;
|
||||
|
||||
JetExpression bodyExpression = function.getBodyExpression();
|
||||
if (bodyExpression == null) return;
|
||||
JetFlowInformationProvider flowInformationProvider = context.getClassDescriptorResolver().computeFlowData((JetElement) function, bodyExpression);
|
||||
JetFlowInformationProvider flowInformationProvider = new JetFlowInformationProvider((JetDeclaration) function, bodyExpression, flowDataTraceFactory, context.getTrace());
|
||||
|
||||
final boolean blockBody = function.hasBlockBody();
|
||||
List<JetElement> unreachableElements = Lists.newArrayList();
|
||||
@@ -95,7 +104,7 @@ public class ControlFlowAnalyzer {
|
||||
@Override
|
||||
public void visitExpression(JetExpression expression) {
|
||||
if (blockBody && expectedReturnType != NO_EXPECTED_TYPE && !JetStandardClasses.isUnit(expectedReturnType) && !rootUnreachableElements.contains(expression)) {
|
||||
JetType type = typeInferrer.getType(scope, expression, expectedReturnType);
|
||||
JetType type = typeInferrerServices.getType(scope, expression, expectedReturnType);
|
||||
if (type == null || !JetStandardClasses.isNothing(type)) {
|
||||
context.getTrace().report(NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY.on(expression));
|
||||
}
|
||||
@@ -103,11 +112,14 @@ public class ControlFlowAnalyzer {
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!declaredLocally) {
|
||||
flowInformationProvider.markUninitializedVariables(function.asElement());
|
||||
}
|
||||
}
|
||||
|
||||
private void checkProperty(JetProperty property) {
|
||||
JetExpression initializer = property.getInitializer();
|
||||
if (initializer == null) return;
|
||||
context.getClassDescriptorResolver().computeFlowData(property, initializer);
|
||||
new JetFlowInformationProvider(property, initializer, flowDataTraceFactory, context.getTrace());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package org.jetbrains.jet.lang.resolve;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.JetSemanticServices;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
@@ -55,13 +55,17 @@ public class TopDownAnalyzer {
|
||||
public ClassObjectStatus setClassObjectDescriptor(@NotNull MutableClassDescriptor classObjectDescriptor) {
|
||||
return ClassObjectStatus.NOT_ALLOWED;
|
||||
}
|
||||
}, Collections.<JetDeclaration>singletonList(object));
|
||||
}, Collections.<JetDeclaration>singletonList(object), JetControlFlowDataTraceFactory.EMPTY, true);
|
||||
}
|
||||
|
||||
public static void process(
|
||||
private static void process(
|
||||
@NotNull JetSemanticServices semanticServices,
|
||||
@NotNull BindingTrace trace,
|
||||
@NotNull JetScope outerScope, NamespaceLike owner, @NotNull List<? extends JetDeclaration> declarations) {
|
||||
@NotNull JetScope outerScope,
|
||||
NamespaceLike owner,
|
||||
@NotNull List<? extends JetDeclaration> declarations,
|
||||
@NotNull JetControlFlowDataTraceFactory flowDataTraceFactory,
|
||||
boolean declaredLocally) {
|
||||
TopDownAnalysisContext context = new TopDownAnalysisContext(semanticServices, trace);
|
||||
new TypeHierarchyResolver(context).process(outerScope, owner, declarations);
|
||||
new DeclarationResolver(context).process();
|
||||
@@ -69,7 +73,17 @@ public class TopDownAnalyzer {
|
||||
new OverrideResolver(context).process();
|
||||
new BodyResolver(context).resolveBehaviorDeclarationBodies();
|
||||
new DeclarationsChecker(context).process();
|
||||
new ControlFlowAnalyzer(context).process();
|
||||
new ControlFlowAnalyzer(context, flowDataTraceFactory, declaredLocally).process();
|
||||
}
|
||||
|
||||
public static void process(
|
||||
@NotNull JetSemanticServices semanticServices,
|
||||
@NotNull BindingTrace trace,
|
||||
@NotNull JetScope outerScope,
|
||||
NamespaceLike owner,
|
||||
@NotNull List<? extends JetDeclaration> declarations,
|
||||
@NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) {
|
||||
process(semanticServices, trace, outerScope, owner, declarations, flowDataTraceFactory, false);
|
||||
}
|
||||
|
||||
public static void processStandardLibraryNamespace(
|
||||
|
||||
@@ -21,9 +21,7 @@ import org.jetbrains.jet.lexer.JetTokens;
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.CONSTRUCTOR;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.DESCRIPTOR_TO_DECLARATION;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.TYPE;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
|
||||
@@ -10,29 +10,29 @@ fun foo() {
|
||||
}
|
||||
---------------------
|
||||
l0:
|
||||
<START>
|
||||
r(Array)
|
||||
r(Array<Int>)
|
||||
w(a)
|
||||
r(3)
|
||||
r(4)
|
||||
r(10)
|
||||
r(a)
|
||||
r(=)
|
||||
w(a[10])
|
||||
r(2)
|
||||
r(10)
|
||||
r(a)
|
||||
r(a[10])
|
||||
r(100)
|
||||
r(10)
|
||||
r(a)
|
||||
r(a[10])
|
||||
r(1)
|
||||
r(+=)
|
||||
w(a[10])
|
||||
<START> NEXT:[r(Array)] PREV:[]
|
||||
r(Array) NEXT:[r(Array<Int>)] PREV:[<START>]
|
||||
r(Array<Int>) NEXT:[w(a)] PREV:[r(Array)]
|
||||
w(a) NEXT:[r(3)] PREV:[r(Array<Int>)]
|
||||
r(3) NEXT:[r(4)] PREV:[w(a)]
|
||||
r(4) NEXT:[r(10)] PREV:[r(3)]
|
||||
r(10) NEXT:[r(a)] PREV:[r(4)]
|
||||
r(a) NEXT:[r(=)] PREV:[r(10)]
|
||||
r(=) NEXT:[w(a[10])] PREV:[r(a)]
|
||||
w(a[10]) NEXT:[r(2)] PREV:[r(=)]
|
||||
r(2) NEXT:[r(10)] PREV:[w(a[10])]
|
||||
r(10) NEXT:[r(a)] PREV:[r(2)]
|
||||
r(a) NEXT:[r(a[10])] PREV:[r(10)]
|
||||
r(a[10]) NEXT:[r(100)] PREV:[r(a)]
|
||||
r(100) NEXT:[r(10)] PREV:[r(a[10])]
|
||||
r(10) NEXT:[r(a)] PREV:[r(100)]
|
||||
r(a) NEXT:[r(a[10])] PREV:[r(10)]
|
||||
r(a[10]) NEXT:[r(1)] PREV:[r(a)]
|
||||
r(1) NEXT:[r(+=)] PREV:[r(a[10])]
|
||||
r(+=) NEXT:[w(a[10])] PREV:[r(1)]
|
||||
w(a[10]) NEXT:[<END>] PREV:[r(+=)]
|
||||
l1:
|
||||
<END>
|
||||
<END> NEXT:[] PREV:[w(a[10])]
|
||||
error:
|
||||
<ERROR>
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
=====================
|
||||
|
||||
@@ -14,44 +14,44 @@ fun assignments() : Unit {
|
||||
}
|
||||
---------------------
|
||||
l0:
|
||||
<START>
|
||||
r(1)
|
||||
w(x)
|
||||
r(2)
|
||||
w(x)
|
||||
r(x)
|
||||
r(2)
|
||||
r(+=)
|
||||
w(x)
|
||||
r(true)
|
||||
jf(l2)
|
||||
r(1)
|
||||
jmp(l3)
|
||||
<START> NEXT:[r(1)] PREV:[]
|
||||
r(1) NEXT:[w(x)] PREV:[<START>]
|
||||
w(x) NEXT:[r(2)] PREV:[r(1)]
|
||||
r(2) NEXT:[w(x)] PREV:[w(x)]
|
||||
w(x) NEXT:[r(x)] PREV:[r(2)]
|
||||
r(x) NEXT:[r(2)] PREV:[w(x)]
|
||||
r(2) NEXT:[r(+=)] PREV:[r(x)]
|
||||
r(+=) NEXT:[w(x)] PREV:[r(2)]
|
||||
w(x) NEXT:[r(true)] PREV:[r(+=)]
|
||||
r(true) NEXT:[jf(l2)] PREV:[w(x)]
|
||||
jf(l2) NEXT:[r(2), r(1)] PREV:[r(true)]
|
||||
r(1) NEXT:[jmp(l3)] PREV:[jf(l2)]
|
||||
jmp(l3) NEXT:[w(x)] PREV:[r(1)]
|
||||
l2:
|
||||
r(2)
|
||||
r(2) NEXT:[w(x)] PREV:[jf(l2)]
|
||||
l3:
|
||||
w(x)
|
||||
r(true)
|
||||
jf(l4)
|
||||
r(false)
|
||||
w(x) NEXT:[r(true)] PREV:[jmp(l3), r(2)]
|
||||
r(true) NEXT:[jf(l4)] PREV:[w(x)]
|
||||
jf(l4) NEXT:[r(true && false), r(false)] PREV:[r(true)]
|
||||
r(false) NEXT:[r(true && false)] PREV:[jf(l4)]
|
||||
l4:
|
||||
r(true && false)
|
||||
w(y)
|
||||
r(false)
|
||||
jf(l5)
|
||||
r(true)
|
||||
r(true && false) NEXT:[w(y)] PREV:[jf(l4), r(false)]
|
||||
w(y) NEXT:[r(false)] PREV:[r(true && false)]
|
||||
r(false) NEXT:[jf(l5)] PREV:[w(y)]
|
||||
jf(l5) NEXT:[r(false && true), r(true)] PREV:[r(false)]
|
||||
r(true) NEXT:[r(false && true)] PREV:[jf(l5)]
|
||||
l5:
|
||||
r(false && true)
|
||||
w(z)
|
||||
r(Test)
|
||||
r(Test())
|
||||
w(t)
|
||||
r(1)
|
||||
r(t)
|
||||
r(=)
|
||||
w(t.x)
|
||||
r(false && true) NEXT:[w(z)] PREV:[jf(l5), r(true)]
|
||||
w(z) NEXT:[r(Test)] PREV:[r(false && true)]
|
||||
r(Test) NEXT:[r(Test())] PREV:[w(z)]
|
||||
r(Test()) NEXT:[w(t)] PREV:[r(Test)]
|
||||
w(t) NEXT:[r(1)] PREV:[r(Test())]
|
||||
r(1) NEXT:[r(t)] PREV:[w(t)]
|
||||
r(t) NEXT:[r(=)] PREV:[r(1)]
|
||||
r(=) NEXT:[w(t.x)] PREV:[r(t)]
|
||||
w(t.x) NEXT:[<END>] PREV:[r(=)]
|
||||
l1:
|
||||
<END>
|
||||
<END> NEXT:[] PREV:[w(t.x)]
|
||||
error:
|
||||
<ERROR>
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
=====================
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
{1}
|
||||
---------------------
|
||||
l2:
|
||||
<START>
|
||||
r(1)
|
||||
<START> NEXT:[r(1)] PREV:[]
|
||||
r(1) NEXT:[<END>] PREV:[<START>]
|
||||
l3:
|
||||
<END>
|
||||
<END> NEXT:[] PREV:[r(1)]
|
||||
error:
|
||||
<ERROR>
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
=====================
|
||||
== f ==
|
||||
fun f(a : Boolean) : Unit {
|
||||
@@ -29,86 +29,86 @@ fun f(a : Boolean) : Unit {
|
||||
}
|
||||
---------------------
|
||||
l0:
|
||||
<START>
|
||||
r(1)
|
||||
r(a)
|
||||
r(2)
|
||||
r(lng)
|
||||
r(2.lng)
|
||||
r(a)
|
||||
r(3)
|
||||
r(foo)
|
||||
r(foo(a, 3))
|
||||
r(genfun)
|
||||
r(genfun<Any>())
|
||||
rf({1})
|
||||
r(flfun)
|
||||
r(flfun {1})
|
||||
r(3)
|
||||
r(4)
|
||||
r(equals)
|
||||
r(equals(4))
|
||||
r(3.equals(4))
|
||||
r(3)
|
||||
r(4)
|
||||
r(equals)
|
||||
r(3 equals 4)
|
||||
r(1)
|
||||
r(2)
|
||||
r(+)
|
||||
r(1 + 2)
|
||||
r(a)
|
||||
jf(l4)
|
||||
r(true)
|
||||
<START> NEXT:[r(1)] PREV:[]
|
||||
r(1) NEXT:[r(a)] PREV:[<START>]
|
||||
r(a) NEXT:[r(2)] PREV:[r(1)]
|
||||
r(2) NEXT:[r(lng)] PREV:[r(a)]
|
||||
r(lng) NEXT:[r(2.lng)] PREV:[r(2)]
|
||||
r(2.lng) NEXT:[r(a)] PREV:[r(lng)]
|
||||
r(a) NEXT:[r(3)] PREV:[r(2.lng)]
|
||||
r(3) NEXT:[r(foo)] PREV:[r(a)]
|
||||
r(foo) NEXT:[r(foo(a, 3))] PREV:[r(3)]
|
||||
r(foo(a, 3)) NEXT:[r(genfun)] PREV:[r(foo)]
|
||||
r(genfun) NEXT:[r(genfun<Any>())] PREV:[r(foo(a, 3))]
|
||||
r(genfun<Any>()) NEXT:[rf({1})] PREV:[r(genfun)]
|
||||
rf({1}) NEXT:[r(flfun)] PREV:[r(genfun<Any>())]
|
||||
r(flfun) NEXT:[r(flfun {1})] PREV:[rf({1})]
|
||||
r(flfun {1}) NEXT:[r(3)] PREV:[r(flfun)]
|
||||
r(3) NEXT:[r(4)] PREV:[r(flfun {1})]
|
||||
r(4) NEXT:[r(equals)] PREV:[r(3)]
|
||||
r(equals) NEXT:[r(equals(4))] PREV:[r(4)]
|
||||
r(equals(4)) NEXT:[r(3.equals(4))] PREV:[r(equals)]
|
||||
r(3.equals(4)) NEXT:[r(3)] PREV:[r(equals(4))]
|
||||
r(3) NEXT:[r(4)] PREV:[r(3.equals(4))]
|
||||
r(4) NEXT:[r(equals)] PREV:[r(3)]
|
||||
r(equals) NEXT:[r(3 equals 4)] PREV:[r(4)]
|
||||
r(3 equals 4) NEXT:[r(1)] PREV:[r(equals)]
|
||||
r(1) NEXT:[r(2)] PREV:[r(3 equals 4)]
|
||||
r(2) NEXT:[r(+)] PREV:[r(1)]
|
||||
r(+) NEXT:[r(1 + 2)] PREV:[r(2)]
|
||||
r(1 + 2) NEXT:[r(a)] PREV:[r(+)]
|
||||
r(a) NEXT:[jf(l4)] PREV:[r(1 + 2)]
|
||||
jf(l4) NEXT:[r(a && true), r(true)] PREV:[r(a)]
|
||||
r(true) NEXT:[r(a && true)] PREV:[jf(l4)]
|
||||
l4:
|
||||
r(a && true)
|
||||
r(a)
|
||||
jt(l5)
|
||||
r(false)
|
||||
r(a && true) NEXT:[r(a)] PREV:[jf(l4), r(true)]
|
||||
r(a) NEXT:[jt(l5)] PREV:[r(a && true)]
|
||||
jt(l5) NEXT:[r(false), r(a || false)] PREV:[r(a)]
|
||||
r(false) NEXT:[r(a || false)] PREV:[jt(l5)]
|
||||
l5:
|
||||
r(a || false)
|
||||
r(a || false) NEXT:[<END>] PREV:[jt(l5), r(false)]
|
||||
l1:
|
||||
<END>
|
||||
<END> NEXT:[] PREV:[r(a || false)]
|
||||
error:
|
||||
<ERROR>
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
l2:
|
||||
<START>
|
||||
r(1)
|
||||
<START> NEXT:[r(1)] PREV:[]
|
||||
r(1) NEXT:[<END>] PREV:[<START>]
|
||||
l3:
|
||||
<END>
|
||||
<END> NEXT:[] PREV:[r(1)]
|
||||
error:
|
||||
<ERROR>
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
=====================
|
||||
== foo ==
|
||||
fun foo(a : Boolean, b : Int) : Unit {}
|
||||
---------------------
|
||||
l0:
|
||||
<START>
|
||||
read (Unit)
|
||||
<START> NEXT:[read (Unit)] PREV:[]
|
||||
read (Unit) NEXT:[<END>] PREV:[<START>]
|
||||
l1:
|
||||
<END>
|
||||
<END> NEXT:[] PREV:[read (Unit)]
|
||||
error:
|
||||
<ERROR>
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
=====================
|
||||
== genfun ==
|
||||
fun genfun<T>() : Unit {}
|
||||
---------------------
|
||||
l0:
|
||||
<START>
|
||||
read (Unit)
|
||||
<START> NEXT:[read (Unit)] PREV:[]
|
||||
read (Unit) NEXT:[<END>] PREV:[<START>]
|
||||
l1:
|
||||
<END>
|
||||
<END> NEXT:[] PREV:[read (Unit)]
|
||||
error:
|
||||
<ERROR>
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
=====================
|
||||
== flfun ==
|
||||
fun flfun(f : fun () : Any) : Unit {}
|
||||
---------------------
|
||||
l0:
|
||||
<START>
|
||||
read (Unit)
|
||||
<START> NEXT:[read (Unit)] PREV:[]
|
||||
read (Unit) NEXT:[<END>] PREV:[<START>]
|
||||
l1:
|
||||
<END>
|
||||
<END> NEXT:[] PREV:[read (Unit)]
|
||||
error:
|
||||
<ERROR>
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
=====================
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
fun empty() {}
|
||||
---------------------
|
||||
l0:
|
||||
<START>
|
||||
read (Unit)
|
||||
<START> NEXT:[read (Unit)] PREV:[]
|
||||
read (Unit) NEXT:[<END>] PREV:[<START>]
|
||||
l1:
|
||||
<END>
|
||||
<END> NEXT:[] PREV:[read (Unit)]
|
||||
error:
|
||||
<ERROR>
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
=====================
|
||||
|
||||
@@ -4,16 +4,16 @@ fun fail() : Nothing {
|
||||
}
|
||||
---------------------
|
||||
l0:
|
||||
<START>
|
||||
r(java)
|
||||
r(lang)
|
||||
r(java.lang)
|
||||
r(RuntimeException)
|
||||
r(RuntimeException())
|
||||
r(java.lang.RuntimeException())
|
||||
jmp(error)
|
||||
<START> NEXT:[r(java)] PREV:[]
|
||||
r(java) NEXT:[r(lang)] PREV:[<START>]
|
||||
r(lang) NEXT:[r(java.lang)] PREV:[r(java)]
|
||||
r(java.lang) NEXT:[r(RuntimeException)] PREV:[r(lang)]
|
||||
r(RuntimeException) NEXT:[r(RuntimeException())] PREV:[r(java.lang)]
|
||||
r(RuntimeException()) NEXT:[r(java.lang.RuntimeException())] PREV:[r(RuntimeException)]
|
||||
r(java.lang.RuntimeException()) NEXT:[jmp(error)] PREV:[r(RuntimeException())]
|
||||
jmp(error) NEXT:[<ERROR>] PREV:[r(java.lang.RuntimeException())]
|
||||
l1:
|
||||
<END>
|
||||
<END> NEXT:[] PREV:[]
|
||||
error:
|
||||
<ERROR>
|
||||
<ERROR> NEXT:[] PREV:[jmp(error)]
|
||||
=====================
|
||||
|
||||
@@ -8,15 +8,15 @@ fun t3() {
|
||||
}
|
||||
---------------------
|
||||
l0:
|
||||
<START>
|
||||
jmp?(l2)
|
||||
r(1)
|
||||
<START> NEXT:[jmp?(l2)] PREV:[]
|
||||
jmp?(l2) NEXT:[r(2), r(1)] PREV:[<START>]
|
||||
r(1) NEXT:[r(2)] PREV:[jmp?(l2)]
|
||||
l2:
|
||||
r(2)
|
||||
r(2) NEXT:[<END>] PREV:[jmp?(l2), r(1)]
|
||||
l1:
|
||||
<END>
|
||||
<END> NEXT:[] PREV:[r(2)]
|
||||
error:
|
||||
<ERROR>
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
=====================
|
||||
== t3 ==
|
||||
fun t3() {
|
||||
@@ -31,26 +31,26 @@ fun t3() {
|
||||
}
|
||||
---------------------
|
||||
l0:
|
||||
<START>
|
||||
jmp?(l2)
|
||||
r(1)
|
||||
r(2)
|
||||
r(3)
|
||||
r(>)
|
||||
r(2 > 3)
|
||||
jf(l3)
|
||||
r(2)
|
||||
ret l1
|
||||
jmp(l4)
|
||||
<START> NEXT:[jmp?(l2)] PREV:[]
|
||||
jmp?(l2) NEXT:[r(2), r(1)] PREV:[<START>]
|
||||
r(1) NEXT:[r(2)] PREV:[jmp?(l2)]
|
||||
r(2) NEXT:[r(3)] PREV:[r(1)]
|
||||
r(3) NEXT:[r(>)] PREV:[r(2)]
|
||||
r(>) NEXT:[r(2 > 3)] PREV:[r(3)]
|
||||
r(2 > 3) NEXT:[jf(l3)] PREV:[r(>)]
|
||||
jf(l3) NEXT:[read (Unit), r(2)] PREV:[r(2 > 3)]
|
||||
r(2) NEXT:[ret l1] PREV:[jf(l3)]
|
||||
ret l1 NEXT:[<END>] PREV:[r(2)]
|
||||
jmp(l4) NEXT:[r(2)] PREV:[]
|
||||
l3:
|
||||
read (Unit)
|
||||
read (Unit) NEXT:[r(2)] PREV:[jf(l3)]
|
||||
l2:
|
||||
l4:
|
||||
r(2)
|
||||
r(2) NEXT:[<END>] PREV:[jmp?(l2), jmp(l4), read (Unit)]
|
||||
l1:
|
||||
<END>
|
||||
<END> NEXT:[] PREV:[ret l1, r(2)]
|
||||
error:
|
||||
<ERROR>
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
=====================
|
||||
== anonymous_0 ==
|
||||
{ () =>
|
||||
@@ -60,21 +60,21 @@ error:
|
||||
}
|
||||
---------------------
|
||||
l3:
|
||||
<START>
|
||||
r(2)
|
||||
r(3)
|
||||
r(>)
|
||||
r(2 > 3)
|
||||
jf(l5)
|
||||
ret l4
|
||||
jmp(l6)
|
||||
<START> NEXT:[r(2)] PREV:[]
|
||||
r(2) NEXT:[r(3)] PREV:[<START>]
|
||||
r(3) NEXT:[r(>)] PREV:[r(2)]
|
||||
r(>) NEXT:[r(2 > 3)] PREV:[r(3)]
|
||||
r(2 > 3) NEXT:[jf(l5)] PREV:[r(>)]
|
||||
jf(l5) NEXT:[read (Unit), ret l4] PREV:[r(2 > 3)]
|
||||
ret l4 NEXT:[<END>] PREV:[jf(l5)]
|
||||
jmp(l6) NEXT:[<END>] PREV:[]
|
||||
l5:
|
||||
read (Unit)
|
||||
read (Unit) NEXT:[<END>] PREV:[jf(l5)]
|
||||
l4:
|
||||
l6:
|
||||
<END>
|
||||
<END> NEXT:[] PREV:[ret l4, jmp(l6), read (Unit)]
|
||||
error:
|
||||
<ERROR>
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
=====================
|
||||
== t3 ==
|
||||
fun t3() {
|
||||
@@ -91,36 +91,36 @@ fun t3() {
|
||||
}
|
||||
---------------------
|
||||
l0:
|
||||
<START>
|
||||
jmp?(l2)
|
||||
r(1)
|
||||
rf({ () =>
|
||||
if (2 > 3) {
|
||||
return@
|
||||
}
|
||||
})
|
||||
<START> NEXT:[jmp?(l2)] PREV:[]
|
||||
jmp?(l2) NEXT:[r(2), r(1)] PREV:[<START>]
|
||||
r(1) NEXT:[rf({ () => if (2 > 3) { retu..)] PREV:[jmp?(l2)]
|
||||
rf({ () =>
|
||||
if (2 > 3) {
|
||||
return@
|
||||
}
|
||||
}) NEXT:[r(2)] PREV:[r(1)]
|
||||
l2:
|
||||
r(2)
|
||||
r(2) NEXT:[<END>] PREV:[jmp?(l2), rf({ () => if (2 > 3) { retu..)]
|
||||
l1:
|
||||
<END>
|
||||
<END> NEXT:[] PREV:[r(2)]
|
||||
error:
|
||||
<ERROR>
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
l3:
|
||||
<START>
|
||||
r(2)
|
||||
r(3)
|
||||
r(>)
|
||||
r(2 > 3)
|
||||
jf(l5)
|
||||
ret l4
|
||||
jmp(l6)
|
||||
<START> NEXT:[r(2)] PREV:[]
|
||||
r(2) NEXT:[r(3)] PREV:[<START>]
|
||||
r(3) NEXT:[r(>)] PREV:[r(2)]
|
||||
r(>) NEXT:[r(2 > 3)] PREV:[r(3)]
|
||||
r(2 > 3) NEXT:[jf(l5)] PREV:[r(>)]
|
||||
jf(l5) NEXT:[read (Unit), ret l4] PREV:[r(2 > 3)]
|
||||
ret l4 NEXT:[<END>] PREV:[jf(l5)]
|
||||
jmp(l6) NEXT:[<END>] PREV:[]
|
||||
l5:
|
||||
read (Unit)
|
||||
read (Unit) NEXT:[<END>] PREV:[jf(l5)]
|
||||
l4:
|
||||
l6:
|
||||
<END>
|
||||
<END> NEXT:[] PREV:[ret l4, jmp(l6), read (Unit)]
|
||||
error:
|
||||
<ERROR>
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
=====================
|
||||
== anonymous_1 ==
|
||||
{ () =>
|
||||
@@ -135,26 +135,26 @@ error:
|
||||
}
|
||||
---------------------
|
||||
l2:
|
||||
<START>
|
||||
jmp?(l4)
|
||||
r(1)
|
||||
r(2)
|
||||
r(3)
|
||||
r(>)
|
||||
r(2 > 3)
|
||||
jf(l5)
|
||||
r(2)
|
||||
ret l3
|
||||
jmp(l6)
|
||||
<START> NEXT:[jmp?(l4)] PREV:[]
|
||||
jmp?(l4) NEXT:[r(2), r(1)] PREV:[<START>]
|
||||
r(1) NEXT:[r(2)] PREV:[jmp?(l4)]
|
||||
r(2) NEXT:[r(3)] PREV:[r(1)]
|
||||
r(3) NEXT:[r(>)] PREV:[r(2)]
|
||||
r(>) NEXT:[r(2 > 3)] PREV:[r(3)]
|
||||
r(2 > 3) NEXT:[jf(l5)] PREV:[r(>)]
|
||||
jf(l5) NEXT:[read (Unit), r(2)] PREV:[r(2 > 3)]
|
||||
r(2) NEXT:[ret l3] PREV:[jf(l5)]
|
||||
ret l3 NEXT:[<END>] PREV:[r(2)]
|
||||
jmp(l6) NEXT:[r(2)] PREV:[]
|
||||
l5:
|
||||
read (Unit)
|
||||
read (Unit) NEXT:[r(2)] PREV:[jf(l5)]
|
||||
l4:
|
||||
l6:
|
||||
r(2)
|
||||
r(2) NEXT:[<END>] PREV:[jmp?(l4), jmp(l6), read (Unit)]
|
||||
l3:
|
||||
<END>
|
||||
<END> NEXT:[] PREV:[ret l3, r(2)]
|
||||
error:
|
||||
<ERROR>
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
=====================
|
||||
== t3 ==
|
||||
fun t3() {
|
||||
@@ -171,42 +171,42 @@ fun t3() {
|
||||
}
|
||||
---------------------
|
||||
l0:
|
||||
<START>
|
||||
rf({ () =>
|
||||
try {
|
||||
1
|
||||
if (2 > 3) {
|
||||
return@
|
||||
}
|
||||
} finally {
|
||||
2
|
||||
}
|
||||
})
|
||||
<START> NEXT:[rf({ () => try { 1 if (2 > 3..)] PREV:[]
|
||||
rf({ () =>
|
||||
try {
|
||||
1
|
||||
if (2 > 3) {
|
||||
return@
|
||||
}
|
||||
} finally {
|
||||
2
|
||||
}
|
||||
}) NEXT:[<END>] PREV:[<START>]
|
||||
l1:
|
||||
<END>
|
||||
<END> NEXT:[] PREV:[rf({ () => try { 1 if (2 > 3..)]
|
||||
error:
|
||||
<ERROR>
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
l2:
|
||||
<START>
|
||||
jmp?(l4)
|
||||
r(1)
|
||||
r(2)
|
||||
r(3)
|
||||
r(>)
|
||||
r(2 > 3)
|
||||
jf(l5)
|
||||
r(2)
|
||||
ret l3
|
||||
jmp(l6)
|
||||
<START> NEXT:[jmp?(l4)] PREV:[]
|
||||
jmp?(l4) NEXT:[r(2), r(1)] PREV:[<START>]
|
||||
r(1) NEXT:[r(2)] PREV:[jmp?(l4)]
|
||||
r(2) NEXT:[r(3)] PREV:[r(1)]
|
||||
r(3) NEXT:[r(>)] PREV:[r(2)]
|
||||
r(>) NEXT:[r(2 > 3)] PREV:[r(3)]
|
||||
r(2 > 3) NEXT:[jf(l5)] PREV:[r(>)]
|
||||
jf(l5) NEXT:[read (Unit), r(2)] PREV:[r(2 > 3)]
|
||||
r(2) NEXT:[ret l3] PREV:[jf(l5)]
|
||||
ret l3 NEXT:[<END>] PREV:[r(2)]
|
||||
jmp(l6) NEXT:[r(2)] PREV:[]
|
||||
l5:
|
||||
read (Unit)
|
||||
read (Unit) NEXT:[r(2)] PREV:[jf(l5)]
|
||||
l4:
|
||||
l6:
|
||||
r(2)
|
||||
r(2) NEXT:[<END>] PREV:[jmp?(l4), jmp(l6), read (Unit)]
|
||||
l3:
|
||||
<END>
|
||||
<END> NEXT:[] PREV:[ret l3, r(2)]
|
||||
error:
|
||||
<ERROR>
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
=====================
|
||||
== t3 ==
|
||||
fun t3() {
|
||||
@@ -223,34 +223,34 @@ fun t3() {
|
||||
}
|
||||
---------------------
|
||||
l0:
|
||||
<START>
|
||||
<START> NEXT:[r(true)] PREV:[]
|
||||
l2:
|
||||
l5:
|
||||
r(true)
|
||||
jf(l3)
|
||||
r(true) NEXT:[jf(l3)] PREV:[<START>, jmp(l2)]
|
||||
jf(l3) NEXT:[read (Unit), jmp?(l6)] PREV:[r(true)]
|
||||
l4:
|
||||
jmp?(l6)
|
||||
r(1)
|
||||
r(2)
|
||||
r(3)
|
||||
r(>)
|
||||
r(2 > 3)
|
||||
jf(l7)
|
||||
r(2)
|
||||
jmp(l3)
|
||||
jmp(l8)
|
||||
jmp?(l6) NEXT:[r(2), r(1)] PREV:[jf(l3)]
|
||||
r(1) NEXT:[r(2)] PREV:[jmp?(l6)]
|
||||
r(2) NEXT:[r(3)] PREV:[r(1)]
|
||||
r(3) NEXT:[r(>)] PREV:[r(2)]
|
||||
r(>) NEXT:[r(2 > 3)] PREV:[r(3)]
|
||||
r(2 > 3) NEXT:[jf(l7)] PREV:[r(>)]
|
||||
jf(l7) NEXT:[read (Unit), r(2)] PREV:[r(2 > 3)]
|
||||
r(2) NEXT:[jmp(l3)] PREV:[jf(l7)]
|
||||
jmp(l3) NEXT:[read (Unit)] PREV:[r(2)]
|
||||
jmp(l8) NEXT:[r(2)] PREV:[]
|
||||
l7:
|
||||
read (Unit)
|
||||
read (Unit) NEXT:[r(2)] PREV:[jf(l7)]
|
||||
l6:
|
||||
l8:
|
||||
r(2)
|
||||
jmp(l2)
|
||||
r(2) NEXT:[jmp(l2)] PREV:[jmp?(l6), jmp(l8), read (Unit)]
|
||||
jmp(l2) NEXT:[r(true)] PREV:[r(2)]
|
||||
l3:
|
||||
read (Unit)
|
||||
read (Unit) NEXT:[<END>] PREV:[jf(l3), jmp(l3)]
|
||||
l1:
|
||||
<END>
|
||||
<END> NEXT:[] PREV:[read (Unit)]
|
||||
error:
|
||||
<ERROR>
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
=====================
|
||||
== t3 ==
|
||||
fun t3() {
|
||||
@@ -268,34 +268,34 @@ fun t3() {
|
||||
}
|
||||
---------------------
|
||||
l0:
|
||||
<START>
|
||||
jmp?(l2)
|
||||
<START> NEXT:[jmp?(l2)] PREV:[]
|
||||
jmp?(l2) NEXT:[r(2), r(true)] PREV:[<START>]
|
||||
l3:
|
||||
l6:
|
||||
r(true)
|
||||
jf(l4)
|
||||
r(true) NEXT:[jf(l4)] PREV:[jmp?(l2), jmp(l3)]
|
||||
jf(l4) NEXT:[read (Unit), r(1)] PREV:[r(true)]
|
||||
l5:
|
||||
r(1)
|
||||
r(2)
|
||||
r(3)
|
||||
r(>)
|
||||
r(2 > 3)
|
||||
jf(l7)
|
||||
jmp(l4)
|
||||
jmp(l8)
|
||||
r(1) NEXT:[r(2)] PREV:[jf(l4)]
|
||||
r(2) NEXT:[r(3)] PREV:[r(1)]
|
||||
r(3) NEXT:[r(>)] PREV:[r(2)]
|
||||
r(>) NEXT:[r(2 > 3)] PREV:[r(3)]
|
||||
r(2 > 3) NEXT:[jf(l7)] PREV:[r(>)]
|
||||
jf(l7) NEXT:[read (Unit), jmp(l4)] PREV:[r(2 > 3)]
|
||||
jmp(l4) NEXT:[read (Unit)] PREV:[jf(l7)]
|
||||
jmp(l8) NEXT:[jmp(l3)] PREV:[]
|
||||
l7:
|
||||
read (Unit)
|
||||
read (Unit) NEXT:[jmp(l3)] PREV:[jf(l7)]
|
||||
l8:
|
||||
jmp(l3)
|
||||
jmp(l3) NEXT:[r(true)] PREV:[jmp(l8), read (Unit)]
|
||||
l4:
|
||||
read (Unit)
|
||||
r(5)
|
||||
read (Unit) NEXT:[r(5)] PREV:[jf(l4), jmp(l4)]
|
||||
r(5) NEXT:[r(2)] PREV:[read (Unit)]
|
||||
l2:
|
||||
r(2)
|
||||
r(2) NEXT:[<END>] PREV:[jmp?(l2), r(5)]
|
||||
l1:
|
||||
<END>
|
||||
<END> NEXT:[] PREV:[r(2)]
|
||||
error:
|
||||
<ERROR>
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
=====================
|
||||
== t3 ==
|
||||
fun t3() {
|
||||
@@ -312,33 +312,33 @@ fun t3() {
|
||||
}
|
||||
---------------------
|
||||
l0:
|
||||
<START>
|
||||
jmp?(l2)
|
||||
<START> NEXT:[jmp?(l2)] PREV:[]
|
||||
jmp?(l2) NEXT:[r(2), r(true)] PREV:[<START>]
|
||||
l3:
|
||||
l6:
|
||||
r(true)
|
||||
jf(l4)
|
||||
r(true) NEXT:[jf(l4)] PREV:[jmp?(l2), jmp(l3)]
|
||||
jf(l4) NEXT:[read (Unit), r(1)] PREV:[r(true)]
|
||||
l5:
|
||||
r(1)
|
||||
r(2)
|
||||
r(3)
|
||||
r(>)
|
||||
r(2 > 3)
|
||||
jf(l7)
|
||||
jmp(l4)
|
||||
jmp(l8)
|
||||
r(1) NEXT:[r(2)] PREV:[jf(l4)]
|
||||
r(2) NEXT:[r(3)] PREV:[r(1)]
|
||||
r(3) NEXT:[r(>)] PREV:[r(2)]
|
||||
r(>) NEXT:[r(2 > 3)] PREV:[r(3)]
|
||||
r(2 > 3) NEXT:[jf(l7)] PREV:[r(>)]
|
||||
jf(l7) NEXT:[read (Unit), jmp(l4)] PREV:[r(2 > 3)]
|
||||
jmp(l4) NEXT:[read (Unit)] PREV:[jf(l7)]
|
||||
jmp(l8) NEXT:[jmp(l3)] PREV:[]
|
||||
l7:
|
||||
read (Unit)
|
||||
read (Unit) NEXT:[jmp(l3)] PREV:[jf(l7)]
|
||||
l8:
|
||||
jmp(l3)
|
||||
jmp(l3) NEXT:[r(true)] PREV:[jmp(l8), read (Unit)]
|
||||
l4:
|
||||
read (Unit)
|
||||
read (Unit) NEXT:[r(2)] PREV:[jf(l4), jmp(l4)]
|
||||
l2:
|
||||
r(2)
|
||||
r(2) NEXT:[<END>] PREV:[jmp?(l2), read (Unit)]
|
||||
l1:
|
||||
<END>
|
||||
<END> NEXT:[] PREV:[r(2)]
|
||||
error:
|
||||
<ERROR>
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
=====================
|
||||
== t3 ==
|
||||
fun t3(a : Int) {
|
||||
@@ -355,37 +355,38 @@ fun t3(a : Int) {
|
||||
}
|
||||
---------------------
|
||||
l0:
|
||||
<START>
|
||||
r(1)
|
||||
r(a)
|
||||
r(..)
|
||||
r(1..a)
|
||||
<START> NEXT:[r(1)] PREV:[]
|
||||
r(1) NEXT:[r(a)] PREV:[<START>]
|
||||
r(a) NEXT:[r(..)] PREV:[r(1)]
|
||||
r(..) NEXT:[r(1..a)] PREV:[r(a)]
|
||||
r(1..a) NEXT:[w(i)] PREV:[r(..)]
|
||||
w(i) NEXT:[jmp?(l2)] PREV:[r(1..a)]
|
||||
l3:
|
||||
jmp?(l2)
|
||||
jmp?(l2) NEXT:[read (Unit), jmp?(l6)] PREV:[w(i)]
|
||||
l4:
|
||||
l5:
|
||||
jmp?(l6)
|
||||
r(1)
|
||||
r(2)
|
||||
r(3)
|
||||
r(>)
|
||||
r(2 > 3)
|
||||
jf(l7)
|
||||
r(2)
|
||||
jmp(l4)
|
||||
jmp(l8)
|
||||
jmp?(l6) NEXT:[r(2), r(1)] PREV:[jmp?(l2), jmp(l4), jmp?(l4)]
|
||||
r(1) NEXT:[r(2)] PREV:[jmp?(l6)]
|
||||
r(2) NEXT:[r(3)] PREV:[r(1)]
|
||||
r(3) NEXT:[r(>)] PREV:[r(2)]
|
||||
r(>) NEXT:[r(2 > 3)] PREV:[r(3)]
|
||||
r(2 > 3) NEXT:[jf(l7)] PREV:[r(>)]
|
||||
jf(l7) NEXT:[read (Unit), r(2)] PREV:[r(2 > 3)]
|
||||
r(2) NEXT:[jmp(l4)] PREV:[jf(l7)]
|
||||
jmp(l4) NEXT:[jmp?(l6)] PREV:[r(2)]
|
||||
jmp(l8) NEXT:[r(2)] PREV:[]
|
||||
l7:
|
||||
read (Unit)
|
||||
read (Unit) NEXT:[r(2)] PREV:[jf(l7)]
|
||||
l6:
|
||||
l8:
|
||||
r(2)
|
||||
jmp?(l4)
|
||||
r(2) NEXT:[jmp?(l4)] PREV:[jmp?(l6), jmp(l8), read (Unit)]
|
||||
jmp?(l4) NEXT:[jmp?(l6), read (Unit)] PREV:[r(2)]
|
||||
l2:
|
||||
read (Unit)
|
||||
read (Unit) NEXT:[<END>] PREV:[jmp?(l2), jmp?(l4)]
|
||||
l1:
|
||||
<END>
|
||||
<END> NEXT:[] PREV:[read (Unit)]
|
||||
error:
|
||||
<ERROR>
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
=====================
|
||||
== t3 ==
|
||||
fun t3(a : Int) {
|
||||
@@ -403,37 +404,38 @@ fun t3(a : Int) {
|
||||
}
|
||||
---------------------
|
||||
l0:
|
||||
<START>
|
||||
jmp?(l2)
|
||||
r(1)
|
||||
r(a)
|
||||
r(..)
|
||||
r(1..a)
|
||||
<START> NEXT:[jmp?(l2)] PREV:[]
|
||||
jmp?(l2) NEXT:[r(2), r(1)] PREV:[<START>]
|
||||
r(1) NEXT:[r(a)] PREV:[jmp?(l2)]
|
||||
r(a) NEXT:[r(..)] PREV:[r(1)]
|
||||
r(..) NEXT:[r(1..a)] PREV:[r(a)]
|
||||
r(1..a) NEXT:[w(i)] PREV:[r(..)]
|
||||
w(i) NEXT:[jmp?(l3)] PREV:[r(1..a)]
|
||||
l4:
|
||||
jmp?(l3)
|
||||
jmp?(l3) NEXT:[read (Unit), r(1)] PREV:[w(i)]
|
||||
l5:
|
||||
l6:
|
||||
r(1)
|
||||
r(2)
|
||||
r(3)
|
||||
r(>)
|
||||
r(2 > 3)
|
||||
jf(l7)
|
||||
jmp(l5)
|
||||
jmp(l8)
|
||||
r(1) NEXT:[r(2)] PREV:[jmp?(l3), jmp(l5), jmp?(l5)]
|
||||
r(2) NEXT:[r(3)] PREV:[r(1)]
|
||||
r(3) NEXT:[r(>)] PREV:[r(2)]
|
||||
r(>) NEXT:[r(2 > 3)] PREV:[r(3)]
|
||||
r(2 > 3) NEXT:[jf(l7)] PREV:[r(>)]
|
||||
jf(l7) NEXT:[read (Unit), jmp(l5)] PREV:[r(2 > 3)]
|
||||
jmp(l5) NEXT:[r(1)] PREV:[jf(l7)]
|
||||
jmp(l8) NEXT:[jmp?(l5)] PREV:[]
|
||||
l7:
|
||||
read (Unit)
|
||||
read (Unit) NEXT:[jmp?(l5)] PREV:[jf(l7)]
|
||||
l8:
|
||||
jmp?(l5)
|
||||
jmp?(l5) NEXT:[r(1), read (Unit)] PREV:[jmp(l8), read (Unit)]
|
||||
l3:
|
||||
read (Unit)
|
||||
r(5)
|
||||
read (Unit) NEXT:[r(5)] PREV:[jmp?(l3), jmp?(l5)]
|
||||
r(5) NEXT:[r(2)] PREV:[read (Unit)]
|
||||
l2:
|
||||
r(2)
|
||||
r(2) NEXT:[<END>] PREV:[jmp?(l2), r(5)]
|
||||
l1:
|
||||
<END>
|
||||
<END> NEXT:[] PREV:[r(2)]
|
||||
error:
|
||||
<ERROR>
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
=====================
|
||||
== t3 ==
|
||||
fun t3(a : Int) {
|
||||
@@ -450,36 +452,37 @@ fun t3(a : Int) {
|
||||
}
|
||||
---------------------
|
||||
l0:
|
||||
<START>
|
||||
jmp?(l2)
|
||||
r(1)
|
||||
r(a)
|
||||
r(..)
|
||||
r(1..a)
|
||||
<START> NEXT:[jmp?(l2)] PREV:[]
|
||||
jmp?(l2) NEXT:[r(2), r(1)] PREV:[<START>]
|
||||
r(1) NEXT:[r(a)] PREV:[jmp?(l2)]
|
||||
r(a) NEXT:[r(..)] PREV:[r(1)]
|
||||
r(..) NEXT:[r(1..a)] PREV:[r(a)]
|
||||
r(1..a) NEXT:[w(i)] PREV:[r(..)]
|
||||
w(i) NEXT:[jmp?(l3)] PREV:[r(1..a)]
|
||||
l4:
|
||||
jmp?(l3)
|
||||
jmp?(l3) NEXT:[read (Unit), r(1)] PREV:[w(i)]
|
||||
l5:
|
||||
l6:
|
||||
r(1)
|
||||
r(2)
|
||||
r(3)
|
||||
r(>)
|
||||
r(2 > 3)
|
||||
jf(l7)
|
||||
jmp(l5)
|
||||
jmp(l8)
|
||||
r(1) NEXT:[r(2)] PREV:[jmp?(l3), jmp(l5), jmp?(l5)]
|
||||
r(2) NEXT:[r(3)] PREV:[r(1)]
|
||||
r(3) NEXT:[r(>)] PREV:[r(2)]
|
||||
r(>) NEXT:[r(2 > 3)] PREV:[r(3)]
|
||||
r(2 > 3) NEXT:[jf(l7)] PREV:[r(>)]
|
||||
jf(l7) NEXT:[read (Unit), jmp(l5)] PREV:[r(2 > 3)]
|
||||
jmp(l5) NEXT:[r(1)] PREV:[jf(l7)]
|
||||
jmp(l8) NEXT:[jmp?(l5)] PREV:[]
|
||||
l7:
|
||||
read (Unit)
|
||||
read (Unit) NEXT:[jmp?(l5)] PREV:[jf(l7)]
|
||||
l8:
|
||||
jmp?(l5)
|
||||
jmp?(l5) NEXT:[r(1), read (Unit)] PREV:[jmp(l8), read (Unit)]
|
||||
l3:
|
||||
read (Unit)
|
||||
read (Unit) NEXT:[r(2)] PREV:[jmp?(l3), jmp?(l5)]
|
||||
l2:
|
||||
r(2)
|
||||
r(2) NEXT:[<END>] PREV:[jmp?(l2), read (Unit)]
|
||||
l1:
|
||||
<END>
|
||||
<END> NEXT:[] PREV:[r(2)]
|
||||
error:
|
||||
<ERROR>
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
=====================
|
||||
== tf ==
|
||||
fun tf() {
|
||||
@@ -492,17 +495,17 @@ fun tf() {
|
||||
}
|
||||
---------------------
|
||||
l0:
|
||||
<START>
|
||||
jmp?(l2)
|
||||
r(1)
|
||||
r(2)
|
||||
ret(*) l1
|
||||
ret(*) l1
|
||||
<START> NEXT:[jmp?(l2)] PREV:[]
|
||||
jmp?(l2) NEXT:[r(2), r(1)] PREV:[<START>]
|
||||
r(1) NEXT:[r(2)] PREV:[jmp?(l2)]
|
||||
r(2) NEXT:[ret(*) l1] PREV:[r(1)]
|
||||
ret(*) l1 NEXT:[<END>] PREV:[r(2)]
|
||||
ret(*) l1 NEXT:[<END>] PREV:[]
|
||||
l2:
|
||||
r(2)
|
||||
ret(*) l1
|
||||
r(2) NEXT:[ret(*) l1] PREV:[jmp?(l2)]
|
||||
ret(*) l1 NEXT:[<END>] PREV:[r(2)]
|
||||
l1:
|
||||
<END>
|
||||
<END> NEXT:[] PREV:[ret(*) l1, ret(*) l1, ret(*) l1]
|
||||
error:
|
||||
<ERROR>
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
=====================
|
||||
|
||||
@@ -18,55 +18,55 @@ fun lazyBooleans(a : Boolean, b : Boolean) : Unit {
|
||||
}
|
||||
---------------------
|
||||
l0:
|
||||
<START>
|
||||
r(a)
|
||||
jf(l2)
|
||||
r(1)
|
||||
jmp(l3)
|
||||
<START> NEXT:[r(a)] PREV:[]
|
||||
r(a) NEXT:[jf(l2)] PREV:[<START>]
|
||||
jf(l2) NEXT:[r(2), r(1)] PREV:[r(a)]
|
||||
r(1) NEXT:[jmp(l3)] PREV:[jf(l2)]
|
||||
jmp(l3) NEXT:[r(3)] PREV:[r(1)]
|
||||
l2:
|
||||
r(2)
|
||||
r(2) NEXT:[r(3)] PREV:[jf(l2)]
|
||||
l3:
|
||||
r(3)
|
||||
r(a)
|
||||
jf(l4)
|
||||
r(b)
|
||||
r(3) NEXT:[r(a)] PREV:[jmp(l3), r(2)]
|
||||
r(a) NEXT:[jf(l4)] PREV:[r(3)]
|
||||
jf(l4) NEXT:[jf(l5), r(b)] PREV:[r(a)]
|
||||
r(b) NEXT:[jf(l5)] PREV:[jf(l4)]
|
||||
l4:
|
||||
jf(l5)
|
||||
r(5)
|
||||
jmp(l6)
|
||||
jf(l5) NEXT:[r(6), r(5)] PREV:[jf(l4), r(b)]
|
||||
r(5) NEXT:[jmp(l6)] PREV:[jf(l5)]
|
||||
jmp(l6) NEXT:[r(7)] PREV:[r(5)]
|
||||
l5:
|
||||
r(6)
|
||||
r(6) NEXT:[r(7)] PREV:[jf(l5)]
|
||||
l6:
|
||||
r(7)
|
||||
r(a)
|
||||
jt(l7)
|
||||
r(b)
|
||||
r(7) NEXT:[r(a)] PREV:[jmp(l6), r(6)]
|
||||
r(a) NEXT:[jt(l7)] PREV:[r(7)]
|
||||
jt(l7) NEXT:[r(b), jf(l8)] PREV:[r(a)]
|
||||
r(b) NEXT:[jf(l8)] PREV:[jt(l7)]
|
||||
l7:
|
||||
jf(l8)
|
||||
r(8)
|
||||
jmp(l9)
|
||||
jf(l8) NEXT:[r(9), r(8)] PREV:[jt(l7), r(b)]
|
||||
r(8) NEXT:[jmp(l9)] PREV:[jf(l8)]
|
||||
jmp(l9) NEXT:[r(10)] PREV:[r(8)]
|
||||
l8:
|
||||
r(9)
|
||||
r(9) NEXT:[r(10)] PREV:[jf(l8)]
|
||||
l9:
|
||||
r(10)
|
||||
r(a)
|
||||
jf(l10)
|
||||
r(11)
|
||||
jmp(l11)
|
||||
r(10) NEXT:[r(a)] PREV:[jmp(l9), r(9)]
|
||||
r(a) NEXT:[jf(l10)] PREV:[r(10)]
|
||||
jf(l10) NEXT:[read (Unit), r(11)] PREV:[r(a)]
|
||||
r(11) NEXT:[jmp(l11)] PREV:[jf(l10)]
|
||||
jmp(l11) NEXT:[r(12)] PREV:[r(11)]
|
||||
l10:
|
||||
read (Unit)
|
||||
read (Unit) NEXT:[r(12)] PREV:[jf(l10)]
|
||||
l11:
|
||||
r(12)
|
||||
r(a)
|
||||
jf(l12)
|
||||
read (Unit)
|
||||
jmp(l13)
|
||||
r(12) NEXT:[r(a)] PREV:[jmp(l11), read (Unit)]
|
||||
r(a) NEXT:[jf(l12)] PREV:[r(12)]
|
||||
jf(l12) NEXT:[r(13), read (Unit)] PREV:[r(a)]
|
||||
read (Unit) NEXT:[jmp(l13)] PREV:[jf(l12)]
|
||||
jmp(l13) NEXT:[r(14)] PREV:[read (Unit)]
|
||||
l12:
|
||||
r(13)
|
||||
r(13) NEXT:[r(14)] PREV:[jf(l12)]
|
||||
l13:
|
||||
r(14)
|
||||
r(14) NEXT:[<END>] PREV:[jmp(l13), r(13)]
|
||||
l1:
|
||||
<END>
|
||||
<END> NEXT:[] PREV:[r(14)]
|
||||
error:
|
||||
<ERROR>
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
=====================
|
||||
|
||||
@@ -6,23 +6,23 @@ fun main() {
|
||||
}
|
||||
---------------------
|
||||
l0:
|
||||
<START>
|
||||
<START> NEXT:[r(1)] PREV:[]
|
||||
l2:
|
||||
l5:
|
||||
r(1)
|
||||
r(0)
|
||||
r(>)
|
||||
r(1 > 0)
|
||||
jf(l3)
|
||||
r(1) NEXT:[r(0)] PREV:[<START>, jmp(l2)]
|
||||
r(0) NEXT:[r(>)] PREV:[r(1)]
|
||||
r(>) NEXT:[r(1 > 0)] PREV:[r(0)]
|
||||
r(1 > 0) NEXT:[jf(l3)] PREV:[r(>)]
|
||||
jf(l3) NEXT:[read (Unit), r(2)] PREV:[r(1 > 0)]
|
||||
l4:
|
||||
r(2)
|
||||
jmp(l2)
|
||||
r(2) NEXT:[jmp(l2)] PREV:[jf(l3)]
|
||||
jmp(l2) NEXT:[r(1)] PREV:[r(2)]
|
||||
l3:
|
||||
read (Unit)
|
||||
read (Unit) NEXT:[<END>] PREV:[jf(l3)]
|
||||
l1:
|
||||
<END>
|
||||
<END> NEXT:[] PREV:[read (Unit)]
|
||||
error:
|
||||
<ERROR>
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
=====================
|
||||
== dowhile ==
|
||||
fun dowhile() {
|
||||
@@ -31,20 +31,20 @@ fun dowhile() {
|
||||
}
|
||||
---------------------
|
||||
l0:
|
||||
<START>
|
||||
<START> NEXT:[ret l1] PREV:[]
|
||||
l2:
|
||||
l4:
|
||||
ret l1
|
||||
ret l1 NEXT:[<END>] PREV:[<START>, jt(l2)]
|
||||
l5:
|
||||
r(1)
|
||||
r(0)
|
||||
r(>)
|
||||
r(1 > 0)
|
||||
jt(l2)
|
||||
r(1) NEXT:[r(0)] PREV:[]
|
||||
r(0) NEXT:[r(>)] PREV:[r(1)]
|
||||
r(>) NEXT:[r(1 > 0)] PREV:[r(0)]
|
||||
r(1 > 0) NEXT:[jt(l2)] PREV:[r(>)]
|
||||
jt(l2) NEXT:[read (Unit), ret l1] PREV:[r(1 > 0)]
|
||||
l3:
|
||||
read (Unit)
|
||||
read (Unit) NEXT:[<END>] PREV:[jt(l2)]
|
||||
l1:
|
||||
<END>
|
||||
<END> NEXT:[] PREV:[ret l1, read (Unit)]
|
||||
error:
|
||||
<ERROR>
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
=====================
|
||||
|
||||
@@ -4,15 +4,15 @@ fun blockAndAndMismatch() : Boolean {
|
||||
}
|
||||
---------------------
|
||||
l0:
|
||||
<START>
|
||||
r(false)
|
||||
jt(l2)
|
||||
r(false)
|
||||
ret(*) l1
|
||||
<START> NEXT:[r(false)] PREV:[]
|
||||
r(false) NEXT:[jt(l2)] PREV:[<START>]
|
||||
jt(l2) NEXT:[r(false), r(false || (return false))] PREV:[r(false)]
|
||||
r(false) NEXT:[ret(*) l1] PREV:[jt(l2)]
|
||||
ret(*) l1 NEXT:[<END>] PREV:[r(false)]
|
||||
l2:
|
||||
r(false || (return false))
|
||||
r(false || (return false)) NEXT:[<END>] PREV:[jt(l2)]
|
||||
l1:
|
||||
<END>
|
||||
<END> NEXT:[] PREV:[ret(*) l1, r(false || (return false))]
|
||||
error:
|
||||
<ERROR>
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
=====================
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
fun short() = 1
|
||||
---------------------
|
||||
l0:
|
||||
<START>
|
||||
r(1)
|
||||
<START> NEXT:[r(1)] PREV:[]
|
||||
r(1) NEXT:[<END>] PREV:[<START>]
|
||||
l1:
|
||||
<END>
|
||||
<END> NEXT:[] PREV:[r(1)]
|
||||
error:
|
||||
<ERROR>
|
||||
<ERROR> NEXT:[] PREV:[]
|
||||
=====================
|
||||
|
||||
@@ -6,8 +6,7 @@ class B() : A() {
|
||||
fun bar() {}
|
||||
}
|
||||
|
||||
fun f9() {
|
||||
val a : A?
|
||||
fun f9(a : A?) {
|
||||
a?.foo()
|
||||
a?.<error descr="Unresolved reference: bar">bar</error>()
|
||||
if (a is B) {
|
||||
@@ -30,8 +29,7 @@ fun f9() {
|
||||
<info descr="Automatically cast to A">a</info>.foo()
|
||||
}
|
||||
|
||||
fun f10() {
|
||||
val a : A?
|
||||
fun f10(a : A?) {
|
||||
if (!(a is B)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
fun box() {
|
||||
val a : C
|
||||
val a : C = C()
|
||||
a.foo()
|
||||
}
|
||||
|
||||
open class A {
|
||||
open class A() {
|
||||
open fun foo() {}
|
||||
}
|
||||
|
||||
open class B : A {
|
||||
open class B() : A() {
|
||||
override fun foo() {}
|
||||
}
|
||||
|
||||
open class C : B {
|
||||
open class C() : B() {
|
||||
override fun foo() {}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ class B() : A() {
|
||||
fun bar() {}
|
||||
}
|
||||
|
||||
fun f9() {
|
||||
val a : A?
|
||||
fun f9(init : A?) {
|
||||
val a : A? = init
|
||||
a?.foo()
|
||||
a?.<!UNRESOLVED_REFERENCE!>bar<!>()
|
||||
if (a is B) {
|
||||
@@ -30,8 +30,8 @@ fun f9() {
|
||||
a.foo()
|
||||
}
|
||||
|
||||
fun f10() {
|
||||
val a : A?
|
||||
fun f10(init : A?) {
|
||||
val a : A? = init
|
||||
if (!(a is B)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
fun box() {
|
||||
val a : C
|
||||
fun box(c : C) {
|
||||
val a : C = c
|
||||
a.foo()
|
||||
}
|
||||
|
||||
|
||||
@@ -10,24 +10,15 @@ import junit.framework.TestSuite;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.JetTestCaseBase;
|
||||
import org.jetbrains.jet.lang.cfg.LoopInfo;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.Instruction;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.JetPseudocodeTrace;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
import org.jetbrains.jet.lang.psi.JetNamedDeclaration;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.*;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacade;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
public class JetControlFlowTest extends JetTestCaseBase {
|
||||
static {
|
||||
@@ -97,20 +88,32 @@ public class JetControlFlowTest extends JetTestCaseBase {
|
||||
for (Pseudocode pseudocode : pseudocodes) {
|
||||
JetElement correspondingElement = pseudocode.getCorrespondingElement();
|
||||
String label;
|
||||
if (correspondingElement instanceof JetNamedDeclaration) {
|
||||
JetNamedDeclaration namedDeclaration = (JetNamedDeclaration) correspondingElement;
|
||||
label = namedDeclaration.getName();
|
||||
assert correspondingElement instanceof JetNamedDeclaration;
|
||||
if (correspondingElement instanceof JetFunctionLiteral) {
|
||||
label = "anonymous_" + i++;
|
||||
}
|
||||
else {
|
||||
label = "anonymous_" + i++;
|
||||
JetNamedDeclaration namedDeclaration = (JetNamedDeclaration) correspondingElement;
|
||||
label = namedDeclaration.getName();
|
||||
}
|
||||
|
||||
instructionDump.append("== ").append(label).append(" ==\n");
|
||||
|
||||
instructionDump.append(correspondingElement.getText());
|
||||
instructionDump.append("\n---------------------\n");
|
||||
pseudocode.dumpInstructions(instructionDump);
|
||||
dumpInstructions(pseudocode, instructionDump);
|
||||
instructionDump.append("=====================\n");
|
||||
|
||||
//check edges directions
|
||||
Collection<Instruction> instructions = pseudocode.getInstructions();
|
||||
for (Instruction instruction : instructions) {
|
||||
for (Instruction nextInstruction : instruction.getNextInstructions()) {
|
||||
assertTrue("instruction: " + instruction + " next: " + nextInstruction, nextInstruction.getPreviousInstructions().contains(instruction));
|
||||
}
|
||||
for (Instruction prevInstruction : instruction.getPreviousInstructions()) {
|
||||
assertTrue("instruction: " + instruction + " prev: " + prevInstruction, prevInstruction.getNextInstructions().contains(instruction));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String expectedInstructionsFileName = getTestDataPath() + "/" + getTestFilePath().replace(".jet", ".instructions");
|
||||
@@ -129,6 +132,218 @@ public class JetControlFlowTest extends JetTestCaseBase {
|
||||
// }
|
||||
}
|
||||
|
||||
public void dfsDump(Pseudocode pseudocode, StringBuilder nodes, StringBuilder edges, Map<Instruction, String> nodeNames) {
|
||||
dfsDump(nodes, edges, pseudocode.getInstructions().get(0), nodeNames);
|
||||
}
|
||||
|
||||
private void dfsDump(StringBuilder nodes, StringBuilder edges, Instruction instruction, Map<Instruction, String> nodeNames) {
|
||||
if (nodeNames.containsKey(instruction)) return;
|
||||
String name = "n" + nodeNames.size();
|
||||
nodeNames.put(instruction, name);
|
||||
nodes.append(name).append(" := ").append(renderName(instruction));
|
||||
|
||||
}
|
||||
|
||||
private String renderName(Instruction instruction) {
|
||||
throw new UnsupportedOperationException(); // TODO
|
||||
}
|
||||
|
||||
private static String formatInstruction(Instruction instruction, int maxLength) {
|
||||
String[] parts = instruction.toString().split("\n");
|
||||
if (parts.length == 1) {
|
||||
return " " + String.format("%1$-" + maxLength + "s", instruction);
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0, partsLength = parts.length; i < partsLength; i++) {
|
||||
String part = parts[i];
|
||||
sb.append(" ").append(String.format("%1$-" + maxLength + "s", part));
|
||||
if (i < partsLength - 1) sb.append("\n");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static String formatInstructionList(Collection<Instruction> instructions) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append('[');
|
||||
for (Iterator<Instruction> iterator = instructions.iterator(); iterator.hasNext(); ) {
|
||||
Instruction instruction = iterator.next();
|
||||
String instructionText = instruction.toString();
|
||||
String[] parts = instructionText.split("\n");
|
||||
if (parts.length > 1) {
|
||||
StringBuilder instructionSb = new StringBuilder();
|
||||
for (String part : parts) {
|
||||
instructionSb.append(part.trim()).append(' ');
|
||||
}
|
||||
if (instructionSb.toString().length() > 30) {
|
||||
sb.append(instructionSb.substring(0, 28)).append("..)");
|
||||
}
|
||||
else {
|
||||
sb.append(instructionSb);
|
||||
}
|
||||
}
|
||||
else {
|
||||
sb.append(instruction);
|
||||
}
|
||||
if (iterator.hasNext()) {
|
||||
sb.append(", ");
|
||||
}
|
||||
}
|
||||
sb.append(']');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void dumpInstructions(Pseudocode pseudocode, @NotNull StringBuilder out) {
|
||||
List<Instruction> instructions = pseudocode.getInstructions();
|
||||
List<Pseudocode.PseudocodeLabel> labels = pseudocode.getLabels();
|
||||
List<Pseudocode> locals = new ArrayList<Pseudocode>();
|
||||
int maxLength = 0;
|
||||
int maxNextLength = 0;
|
||||
for (Instruction instruction : instructions) {
|
||||
String instuctionText = instruction.toString();
|
||||
if (instuctionText.length() > maxLength) {
|
||||
String[] parts = instuctionText.split("\n");
|
||||
if (parts.length > 1) {
|
||||
for (String part : parts) {
|
||||
if (part.length() > maxLength) {
|
||||
maxLength = part.length();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
maxLength = instuctionText.length();
|
||||
}
|
||||
}
|
||||
String instructionListText = formatInstructionList(instruction.getNextInstructions());
|
||||
if (instructionListText.length() > maxNextLength) {
|
||||
maxNextLength = instructionListText.length();
|
||||
}
|
||||
}
|
||||
for (int i = 0, instructionsSize = instructions.size(); i < instructionsSize; i++) {
|
||||
Instruction instruction = instructions.get(i);
|
||||
if (instruction instanceof LocalDeclarationInstruction) {
|
||||
LocalDeclarationInstruction localDeclarationInstruction = (LocalDeclarationInstruction) instruction;
|
||||
locals.add(localDeclarationInstruction.getBody());
|
||||
}
|
||||
for (Pseudocode.PseudocodeLabel label: labels) {
|
||||
if (label.getTargetInstructionIndex() == i) {
|
||||
out.append(label.getName()).append(":\n");
|
||||
}
|
||||
}
|
||||
|
||||
out.append(formatInstruction(instruction, maxLength)).
|
||||
append(" NEXT:").append(String.format("%1$-" + maxNextLength + "s", formatInstructionList(instruction.getNextInstructions()))).
|
||||
append(" PREV:").append(formatInstructionList(instruction.getPreviousInstructions())).append("\n");
|
||||
}
|
||||
for (Pseudocode local : locals) {
|
||||
dumpInstructions(local, out);
|
||||
}
|
||||
}
|
||||
|
||||
public void dumpEdges(List<Instruction> instructions, final PrintStream out, final int[] count, final Map<Instruction, String> nodeToName) {
|
||||
for (final Instruction fromInst : instructions) {
|
||||
fromInst.accept(new InstructionVisitor() {
|
||||
@Override
|
||||
public void visitFunctionLiteralValue(LocalDeclarationInstruction instruction) {
|
||||
int index = count[0];
|
||||
// instruction.getBody().dumpSubgraph(out, "subgraph cluster_" + index, count, "color=blue;\nlabel = \"f" + index + "\";", nodeToName);
|
||||
printEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getBody().getInstructions().get(0)), null);
|
||||
visitInstructionWithNext(instruction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitUnconditionalJump(UnconditionalJumpInstruction instruction) {
|
||||
// Nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJump(AbstractJumpInstruction instruction) {
|
||||
printEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getResolvedTarget()), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNondeterministicJump(NondeterministicJumpInstruction instruction) {
|
||||
//todo print edges
|
||||
visitInstruction(instruction);
|
||||
printEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getNext()), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReturnValue(ReturnValueInstruction instruction) {
|
||||
super.visitReturnValue(instruction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReturnNoValue(ReturnNoValueInstruction instruction) {
|
||||
super.visitReturnNoValue(instruction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitConditionalJump(ConditionalJumpInstruction instruction) {
|
||||
String from = nodeToName.get(instruction);
|
||||
printEdge(out, from, nodeToName.get(instruction.getNextOnFalse()), "no");
|
||||
printEdge(out, from, nodeToName.get(instruction.getNextOnTrue()), "yes");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInstructionWithNext(InstructionWithNext instruction) {
|
||||
printEdge(out, nodeToName.get(instruction), nodeToName.get(instruction.getNext()), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSubroutineExit(SubroutineExitInstruction instruction) {
|
||||
// Nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInstruction(Instruction instruction) {
|
||||
throw new UnsupportedOperationException(instruction.toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void dumpNodes(List<Instruction> instructions, PrintStream out, int[] count, Map<Instruction, String> nodeToName) {
|
||||
for (Instruction node : instructions) {
|
||||
if (node instanceof UnconditionalJumpInstruction) {
|
||||
continue;
|
||||
}
|
||||
String name = "n" + count[0]++;
|
||||
nodeToName.put(node, name);
|
||||
String text = node.toString();
|
||||
int newline = text.indexOf("\n");
|
||||
if (newline >= 0) {
|
||||
text = text.substring(0, newline);
|
||||
}
|
||||
String shape = "box";
|
||||
if (node instanceof ConditionalJumpInstruction) {
|
||||
shape = "diamond";
|
||||
}
|
||||
else if (node instanceof NondeterministicJumpInstruction) {
|
||||
shape = "Mdiamond";
|
||||
}
|
||||
else if (node instanceof UnsupportedElementInstruction) {
|
||||
shape = "box, fillcolor=red, style=filled";
|
||||
}
|
||||
else if (node instanceof LocalDeclarationInstruction) {
|
||||
shape = "Mcircle";
|
||||
}
|
||||
else if (node instanceof SubroutineEnterInstruction || node instanceof SubroutineExitInstruction) {
|
||||
shape = "roundrect, style=rounded";
|
||||
}
|
||||
out.println(name + "[label=\"" + text + "\", shape=" + shape + "];");
|
||||
}
|
||||
}
|
||||
|
||||
private void printEdge(PrintStream out, String from, String to, String label) {
|
||||
if (label != null) {
|
||||
label = "[label=\"" + label + "\"]";
|
||||
}
|
||||
else {
|
||||
label = "";
|
||||
}
|
||||
out.println(from + " -> " + to + label + ";");
|
||||
}
|
||||
|
||||
private void dumpDot(String name, Collection<Pseudocode> pseudocodes) throws FileNotFoundException {
|
||||
String graphFileName = getTestDataPath() + "/" + getTestFilePath().replace(".jet", ".dot");
|
||||
File target = new File(graphFileName);
|
||||
@@ -139,7 +354,7 @@ public class JetControlFlowTest extends JetTestCaseBase {
|
||||
int[] count = new int[1];
|
||||
Map<Instruction, String> nodeToName = new HashMap<Instruction, String>();
|
||||
for (Pseudocode pseudocode : pseudocodes) {
|
||||
pseudocode.dumpNodes(out, count, nodeToName);
|
||||
dumpNodes(pseudocode.getInstructions(), out, count, nodeToName);
|
||||
}
|
||||
int i = 0;
|
||||
for (Pseudocode pseudocode : pseudocodes) {
|
||||
@@ -155,7 +370,7 @@ public class JetControlFlowTest extends JetTestCaseBase {
|
||||
out.println("subgraph cluster_" + i + " {\n" +
|
||||
"label=\"" + label + "\";\n" +
|
||||
"color=blue;\n");
|
||||
pseudocode.dumpEdges(out, count, nodeToName);
|
||||
dumpEdges(pseudocode.getInstructions(), out, count, nodeToName);
|
||||
out.println("}");
|
||||
i++;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* @author alex.tkachman
|
||||
*/
|
||||
@@ -13,4 +16,29 @@ public class FunctionGenTest extends CodegenTestCase {
|
||||
blackBoxFile("functions/nothisnoclosure.jet");
|
||||
System.out.println(generateToText());
|
||||
}
|
||||
|
||||
public void testAnyToString () throws InvocationTargetException, IllegalAccessException {
|
||||
loadText("fun foo(x: Any) = x.toString()");
|
||||
System.out.println(generateToText());
|
||||
Method foo = generateFunction();
|
||||
assertEquals("something", foo.invoke(null, "something"));
|
||||
assertEquals("null", foo.invoke(null, new Object[]{null}));
|
||||
|
||||
}
|
||||
|
||||
public void testAnyEqualsNullable () throws InvocationTargetException, IllegalAccessException {
|
||||
loadText("fun foo(x: Any?) = x.equals(\"lala\")");
|
||||
System.out.println(generateToText());
|
||||
Method foo = generateFunction();
|
||||
assertTrue((Boolean) foo.invoke(null, "lala"));
|
||||
assertFalse((Boolean) foo.invoke(null, "mama"));
|
||||
}
|
||||
|
||||
public void testAnyEquals () throws InvocationTargetException, IllegalAccessException {
|
||||
loadText("fun foo(x: Any) = x.equals(\"lala\")");
|
||||
System.out.println(generateToText());
|
||||
Method foo = generateFunction();
|
||||
assertTrue((Boolean) foo.invoke(null, "lala"));
|
||||
assertFalse((Boolean) foo.invoke(null, "mama"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package jet.arrays;
|
||||
|
||||
import jet.Iterator;
|
||||
import jet.JetObject;
|
||||
import jet.typeinfo.TypeInfo;
|
||||
import jet.typeinfo.TypeInfoProjection;
|
||||
|
||||
@@ -10,7 +11,7 @@ import java.util.Arrays;
|
||||
/**
|
||||
* @author alex.tkachman
|
||||
*/
|
||||
public abstract class ArrayIterator<T> implements Iterator<T> {
|
||||
public abstract class ArrayIterator<T> implements Iterator<T>, JetObject {
|
||||
private final int size;
|
||||
protected int index;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user