diff --git a/.idea/modules.xml b/.idea/modules.xml
index d171cde374e..cf9e7a92cb7 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -7,6 +7,7 @@
+
diff --git a/compiler/frontend/src/org/jetbrains/jet/JetNodeTypes.java b/compiler/frontend/src/org/jetbrains/jet/JetNodeTypes.java
index f58817258be..cc2f2d80824 100644
--- a/compiler/frontend/src/org/jetbrains/jet/JetNodeTypes.java
+++ b/compiler/frontend/src/org/jetbrains/jet/JetNodeTypes.java
@@ -3,16 +3,20 @@
*/
package org.jetbrains.jet;
+import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.IFileElementType;
-import org.jetbrains.jet.plugin.JetLanguage;
import org.jetbrains.jet.lang.psi.*;
+import org.jetbrains.jet.lang.psi.stubs.elements.JetStubElementTypes;
+import org.jetbrains.jet.plugin.JetLanguage;
public interface JetNodeTypes {
IFileElementType JET_FILE = new IFileElementType(JetLanguage.INSTANCE);
- JetNodeType CLASS = new JetNodeType("CLASS", JetClass.class);
+ IElementType CLASS = JetStubElementTypes.CLASS;
+ IElementType FUN = JetStubElementTypes.FUNCTION;
+
JetNodeType PROPERTY = new JetNodeType("PROPERTY", JetProperty.class);
- JetNodeType FUN = new JetNodeType("FUN", JetNamedFunction.class);
+
JetNodeType TYPEDEF = new JetNodeType("TYPEDEF", JetTypedef.class);
JetNodeType OBJECT_DECLARATION = new JetNodeType("OBJECT_DECLARATION", JetObjectDeclaration.class);
JetNodeType OBJECT_DECLARATION_NAME = new JetNodeType("OBJECT_DECLARATION_NAME", JetObjectDeclarationName.class);
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java
index 7c2d367f74e..697d2ce4182 100644
--- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java
@@ -220,7 +220,7 @@ public class JetExpressionParsing extends AbstractJetParsing {
usedSet.removeAll(opSet);
- assert usedSet.isEmpty() : "" + usedSet;
+ assert usedSet.isEmpty() : usedSet.toString();
}
@@ -239,9 +239,7 @@ public class JetExpressionParsing extends AbstractJetParsing {
Precedence precedence = Precedence.ELVIS;
while (precedence != null) {
IElementType[] types = precedence.getOperations().getTypes();
- for (IElementType type : types) {
- elvisFollow.add(type);
- }
+ Collections.addAll(elvisFollow, types);
precedence = precedence.higher;
}
decomposerExpressionFollow = TokenSet.orSet(EXPRESSION_FOLLOW, TokenSet.create(elvisFollow.toArray(new IElementType[elvisFollow.size()])));
@@ -1052,7 +1050,7 @@ public class JetExpressionParsing extends AbstractJetParsing {
JetParsing.TokenDetector enumDetector = new JetParsing.TokenDetector(ENUM_KEYWORD);
myJetParsing.parseModifierList(MODIFIER_LIST, enumDetector, false);
- JetNodeType declType = parseLocalDeclarationRest(enumDetector.isDetected());
+ IElementType declType = parseLocalDeclarationRest(enumDetector.isDetected());
if (declType != null) {
decl.done(declType);
@@ -1369,9 +1367,9 @@ public class JetExpressionParsing extends AbstractJetParsing {
* : object
* ;
*/
- private JetNodeType parseLocalDeclarationRest(boolean isEnum) {
+ private IElementType parseLocalDeclarationRest(boolean isEnum) {
IElementType keywordToken = tt();
- JetNodeType declType = null;
+ IElementType declType = null;
if (keywordToken == CLASS_KEYWORD || keywordToken == TRAIT_KEYWORD) {
declType = myJetParsing.parseClass(isEnum);
}
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParserDefinition.java b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParserDefinition.java
index 317ad356d04..9ee73e0aeba 100644
--- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParserDefinition.java
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParserDefinition.java
@@ -3,11 +3,11 @@
*/
package org.jetbrains.jet.lang.parsing;
-import com.intellij.extapi.psi.ASTWrapperPsiElement;
import com.intellij.lang.ASTNode;
import com.intellij.lang.ParserDefinition;
import com.intellij.lang.PsiParser;
import com.intellij.lexer.Lexer;
+import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.psi.FileViewProvider;
import com.intellij.psi.PsiElement;
@@ -18,10 +18,30 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.JetNodeType;
import org.jetbrains.jet.JetNodeTypes;
import org.jetbrains.jet.lang.psi.JetFile;
+import org.jetbrains.jet.lang.psi.stubs.elements.JetFakeStubElementFactory;
+import org.jetbrains.jet.lang.psi.stubs.elements.JetStubElementFactory;
+import org.jetbrains.jet.lang.psi.stubs.elements.JetStubElementType;
import org.jetbrains.jet.lexer.JetLexer;
import org.jetbrains.jet.lexer.JetTokens;
public class JetParserDefinition implements ParserDefinition {
+
+ // TODO (stubs):
+ private static JetStubElementFactory stubElementFactory = new JetFakeStubElementFactory();
+
+ public static void setStubFactory(JetStubElementFactory factory) {
+ stubElementFactory = factory;
+ }
+
+ public static JetStubElementFactory getStubElementTypeFactory() {
+ return stubElementFactory;
+ }
+
+ public JetParserDefinition() {
+ if (!ApplicationManager.getApplication().isCommandLine()) {
+ }
+ }
+
@NotNull
public Lexer createLexer(Project project) {
return new JetLexer();
@@ -32,7 +52,9 @@ public class JetParserDefinition implements ParserDefinition {
}
public IFileElementType getFileNodeType() {
+ // TODO (stubs)
return JetNodeTypes.JET_FILE;
+ // return JetStubElementTypes.FILE;
}
@NotNull
@@ -52,6 +74,10 @@ public class JetParserDefinition implements ParserDefinition {
@NotNull
public PsiElement createElement(ASTNode astNode) {
+ if (astNode.getElementType() instanceof JetStubElementType) {
+ return ((JetStubElementType) astNode.getElementType()).createPsiFromAst(astNode);
+ }
+
return ((JetNodeType) astNode.getElementType()).createPsi(astNode);
}
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java
index 153cc928d49..38b4f2c7479 100644
--- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java
@@ -232,7 +232,7 @@ public class JetParsing extends AbstractJetParsing {
parseModifierList(MODIFIER_LIST, detector, true);
IElementType keywordToken = tt();
- JetNodeType declType = null;
+ IElementType declType = null;
// if (keywordToken == PACKAGE_KEYWORD) {
// declType = parseNamespaceBlock();
// }
@@ -385,7 +385,7 @@ public class JetParsing extends AbstractJetParsing {
* (classBody? | enumClassBody)
* ;
*/
- public JetNodeType parseClass(boolean enumClass) {
+ public IElementType parseClass(boolean enumClass) {
assert _atSet(CLASS_KEYWORD, TRAIT_KEYWORD);
advance(); // CLASS_KEYWORD or TRAIT_KEYWORD
@@ -558,7 +558,7 @@ public class JetParsing extends AbstractJetParsing {
TokenDetector enumDetector = new TokenDetector(ENUM_KEYWORD);
parseModifierList(MODIFIER_LIST, enumDetector, true);
- JetNodeType declType = parseMemberDeclarationRest(enumDetector.isDetected());
+ IElementType declType = parseMemberDeclarationRest(enumDetector.isDetected());
if (declType == null) {
errorAndAdvance("Expecting member declaration");
@@ -569,9 +569,9 @@ public class JetParsing extends AbstractJetParsing {
}
}
- private JetNodeType parseMemberDeclarationRest(boolean isEnum) {
+ private IElementType parseMemberDeclarationRest(boolean isEnum) {
IElementType keywordToken = tt();
- JetNodeType declType = null;
+ IElementType declType = null;
if (keywordToken == CLASS_KEYWORD) {
if (lookahead(1) == OBJECT_KEYWORD) {
declType = parseClassObject();
@@ -925,7 +925,7 @@ public class JetParsing extends AbstractJetParsing {
* functionBody?
* ;
*/
- public JetNodeType parseFunction() {
+ public IElementType parseFunction() {
assert _at(FUN_KEYWORD);
advance(); // FUN_KEYWORD
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClass.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClass.java
index 81f1dc63fae..818eaf7a907 100644
--- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClass.java
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClass.java
@@ -1,9 +1,13 @@
package org.jetbrains.jet.lang.psi;
import com.intellij.lang.ASTNode;
+import com.intellij.psi.StubBasedPsiElement;
+import com.intellij.psi.stubs.IStubElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes;
+import org.jetbrains.jet.lang.psi.stubs.PsiJetClassStub;
+import org.jetbrains.jet.lang.psi.stubs.elements.JetStubElementTypes;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.Collections;
@@ -12,11 +16,20 @@ import java.util.List;
/**
* @author max
*/
-public class JetClass extends JetTypeParameterListOwner implements JetClassOrObject, JetModifierListOwner {
+public class JetClass extends JetTypeParameterListOwner
+ implements JetClassOrObject, JetModifierListOwner, StubBasedPsiElement> {
+
+ private PsiJetClassStub stub;
+
public JetClass(@NotNull ASTNode node) {
super(node);
}
+ // TODO (stubs)
+// public JetClass(final PsiJetClassStub stub) {
+// this.stub = stub;
+// }
+
@Override
public List getDeclarations() {
JetClassBody body = (JetClassBody) findChildByType(JetNodeTypes.CLASS_BODY);
@@ -112,4 +125,16 @@ public class JetClass extends JetTypeParameterListOwner implements JetClassOrObj
public boolean isTrait() {
return findChildByType(JetTokens.TRAIT_KEYWORD) != null;
}
+
+ @Override
+ public IStubElementType getElementType() {
+ // TODO (stubs)
+ return JetStubElementTypes.CLASS;
+ }
+
+ @Override
+ public PsiJetClassStub> getStub() {
+ // TODO (stubs)
+ return null;
+ }
}
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFunction.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFunction.java
index 52c987ea24f..67b0b7c6b85 100644
--- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFunction.java
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFunction.java
@@ -14,7 +14,9 @@ import java.util.List;
/**
* @author abreslav
*/
-abstract public class JetFunction extends JetTypeParameterListOwner implements JetDeclarationWithBody, JetModifierListOwner {
+abstract public class JetFunction extends JetTypeParameterListOwner
+ implements JetDeclarationWithBody, JetModifierListOwner {
+
public JetFunction(@NotNull ASTNode node) {
super(node);
}
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetNamedFunction.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetNamedFunction.java
index 30ffa3b5248..3786dfe3fc6 100644
--- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetNamedFunction.java
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetNamedFunction.java
@@ -2,13 +2,17 @@ package org.jetbrains.jet.lang.psi;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
+import com.intellij.psi.StubBasedPsiElement;
+import com.intellij.psi.stubs.IStubElementType;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jet.lang.psi.stubs.PsiJetFunctionStub;
+import org.jetbrains.jet.lang.psi.stubs.elements.JetStubElementTypes;
import org.jetbrains.jet.lexer.JetTokens;
/**
* @author max
*/
-public class JetNamedFunction extends JetFunction {
+public class JetNamedFunction extends JetFunction implements StubBasedPsiElement> {
public JetNamedFunction(@NotNull ASTNode node) {
super(node);
}
@@ -62,4 +66,14 @@ public class JetNamedFunction extends JetFunction {
return this;
}
+ @Override
+ public IStubElementType getElementType() {
+ return JetStubElementTypes.FUNCTION;
+ }
+
+ @Override
+ public PsiJetFunctionStub> getStub() {
+ // TODO (stubs)
+ return null;
+ }
}
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/PsiJetClassStub.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/PsiJetClassStub.java
new file mode 100644
index 00000000000..36899124b73
--- /dev/null
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/PsiJetClassStub.java
@@ -0,0 +1,21 @@
+package org.jetbrains.jet.lang.psi.stubs;
+
+import com.intellij.psi.stubs.StubElement;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.jet.lang.psi.JetClass;
+
+/**
+ * @author Nikolay Krasko
+ */
+public interface PsiJetClassStub extends StubElement {
+ @NonNls
+ @Nullable
+ String getQualifiedName();
+
+ @Nullable
+ String getName();
+
+ boolean isDeprecated();
+ boolean hasDeprecatedAnnotation();
+}
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/PsiJetFileStub.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/PsiJetFileStub.java
new file mode 100644
index 00000000000..77108284e13
--- /dev/null
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/PsiJetFileStub.java
@@ -0,0 +1,15 @@
+package org.jetbrains.jet.lang.psi.stubs;
+
+import com.intellij.psi.impl.java.stubs.StubPsiFactory;
+import com.intellij.psi.stubs.PsiClassHolderFileStub;
+import org.jetbrains.jet.lang.psi.JetFile;
+
+/**
+ * @author Nikolay Krasko
+ */
+public interface PsiJetFileStub extends PsiClassHolderFileStub {
+ String getPackageName();
+
+ StubPsiFactory getPsiFactory();
+ void setPsiFactory(StubPsiFactory factory);
+}
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/PsiJetFunctionStub.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/PsiJetFunctionStub.java
new file mode 100644
index 00000000000..3d8af9463a4
--- /dev/null
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/PsiJetFunctionStub.java
@@ -0,0 +1,22 @@
+package org.jetbrains.jet.lang.psi.stubs;
+
+import com.intellij.psi.stubs.StubElement;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.jet.lang.psi.JetFunction;
+
+/**
+ * @author Nikolay Krasko
+ */
+public interface PsiJetFunctionStub extends StubElement {
+ @Nullable
+ String getName();
+
+ boolean isDeclaration();
+
+ @NotNull
+ String[] getAnnotations();
+
+ @NotNull
+ String getReturnTypeText();
+}
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetClassElementType.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetClassElementType.java
new file mode 100644
index 00000000000..8ed623b10a9
--- /dev/null
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetClassElementType.java
@@ -0,0 +1,70 @@
+package org.jetbrains.jet.lang.psi.stubs.elements;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.lang.LighterAST;
+import com.intellij.lang.LighterASTNode;
+import com.intellij.psi.stubs.IndexSink;
+import com.intellij.psi.stubs.StubElement;
+import com.intellij.psi.stubs.StubInputStream;
+import com.intellij.psi.stubs.StubOutputStream;
+import com.intellij.util.io.StringRef;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jet.lang.psi.JetClass;
+import org.jetbrains.jet.lang.psi.stubs.PsiJetClassStub;
+import org.jetbrains.jet.lang.psi.stubs.impl.PsiJetClassStubImpl;
+import org.jetbrains.jet.plugin.JetLanguage;
+
+import java.io.IOException;
+
+/**
+ * @author Nikolay Krasko
+ */
+public abstract class JetClassElementType extends JetStubElementType {
+
+ public JetClassElementType(@NotNull @NonNls String debugName) {
+ super(debugName, JetLanguage.INSTANCE);
+ }
+
+ @Override
+ public PsiJetClassStub createStub(LighterAST tree, LighterASTNode node, StubElement parentStub) {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public JetClass createPsi(@NotNull PsiJetClassStub stub) {
+ // TODO: Don't work for kotlin classes
+ // return getPsiFactory(stub).createClass(stub);
+ return null;
+ }
+
+ @Override
+ public JetClass createPsiFromAst(@NotNull ASTNode node) {
+ return new JetClass(node);
+ }
+
+ @Override
+ public PsiJetClassStub createStub(@NotNull JetClass psi, StubElement parentStub) {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public void serialize(PsiJetClassStub stub, StubOutputStream dataStream) throws IOException {
+ dataStream.writeName(stub.getName());
+ dataStream.writeName(stub.getQualifiedName());
+ }
+
+ @Override
+ public PsiJetClassStub deserialize(StubInputStream dataStream, StubElement parentStub) throws IOException {
+ final StringRef name = dataStream.readName();
+ final StringRef qualifiedName = dataStream.readName();
+
+ final JetClassElementType type = JetStubElementTypes.CLASS;
+ final PsiJetClassStubImpl classStub = new PsiJetClassStubImpl(type, parentStub, qualifiedName, name);
+
+ return classStub;
+ }
+
+ @Override
+ public abstract void indexStub(PsiJetClassStub stub, IndexSink sink);
+}
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetFakeStubElementFactory.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetFakeStubElementFactory.java
new file mode 100644
index 00000000000..29c8e566f5c
--- /dev/null
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetFakeStubElementFactory.java
@@ -0,0 +1,28 @@
+package org.jetbrains.jet.lang.psi.stubs.elements;
+
+import com.intellij.psi.stubs.IndexSink;
+import org.jetbrains.jet.lang.psi.stubs.PsiJetClassStub;
+import org.jetbrains.jet.lang.psi.stubs.PsiJetFunctionStub;
+
+/**
+ * @author Nikolay Krasko
+ */
+public class JetFakeStubElementFactory implements JetStubElementFactory {
+ @Override
+ public JetClassElementType getClassElementType() {
+ return new JetClassElementType("CLASS") {
+ @Override
+ public void indexStub(PsiJetClassStub stub, IndexSink sink) {
+ }
+ };
+ }
+
+ @Override
+ public JetFunctionElementType getFunctionElementType() {
+ return new JetFunctionElementType("FUN") {
+ @Override
+ public void indexStub(PsiJetFunctionStub stub, IndexSink sink) {
+ }
+ };
+ }
+}
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetFileElementType.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetFileElementType.java
new file mode 100644
index 00000000000..c8a5ce58bd1
--- /dev/null
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetFileElementType.java
@@ -0,0 +1,74 @@
+package org.jetbrains.jet.lang.psi.stubs.elements;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.StubBuilder;
+import com.intellij.psi.stubs.IndexSink;
+import com.intellij.psi.stubs.StubElement;
+import com.intellij.psi.stubs.StubInputStream;
+import com.intellij.psi.stubs.StubOutputStream;
+import com.intellij.psi.tree.IStubFileElementType;
+import com.intellij.util.io.StringRef;
+import org.jetbrains.jet.lang.psi.stubs.PsiJetFileStub;
+import org.jetbrains.jet.lang.psi.stubs.impl.PsiJetFileStubImpl;
+import org.jetbrains.jet.plugin.JetLanguage;
+
+import java.io.IOException;
+
+/**
+ * @author Nikolay Krasko
+ */
+public class JetFileElementType extends IStubFileElementType {
+ public static final int STUB_VERSION = 1;
+
+ public JetFileElementType() {
+ super("jet.FILE", JetLanguage.INSTANCE);
+ }
+
+ @Override
+ public StubBuilder getBuilder() {
+ return new JetFileStubBuilder();
+ }
+
+ @Override
+ public int getStubVersion() {
+ return STUB_VERSION;
+ }
+
+ @Override
+ public boolean shouldBuildStubFor(final VirtualFile file) {
+ // TODO:
+ return true;
+
+// final VirtualFile dir = file.getParent();
+// return dir == null || dir.getUserData(LanguageLevel.KEY) != null;
+ }
+
+ @Override
+ public ASTNode createNode(final CharSequence text) {
+ // TODO (stub):
+ return super.createNode(text);
+ }
+
+ @Override
+ public String getExternalId() {
+ return "jet.FILE";
+ }
+
+ @Override
+ public void serialize(final PsiJetFileStub stub, final StubOutputStream dataStream)
+ throws IOException {
+ dataStream.writeName(stub.getPackageName());
+ }
+
+ @Override
+ public PsiJetFileStub deserialize(final StubInputStream dataStream, final StubElement parentStub) throws IOException {
+ StringRef packName = dataStream.readName();
+ return new PsiJetFileStubImpl(null, packName);
+ }
+
+ @Override
+ public void indexStub(final PsiJetFileStub stub, final IndexSink sink) {
+ // Don't index file
+ }
+}
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetFileStubBuilder.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetFileStubBuilder.java
new file mode 100644
index 00000000000..2b93cb40860
--- /dev/null
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetFileStubBuilder.java
@@ -0,0 +1,37 @@
+package org.jetbrains.jet.lang.psi.stubs.elements;
+
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.stubs.DefaultStubBuilder;
+import com.intellij.psi.stubs.StubElement;
+import com.intellij.util.io.StringRef;
+import org.jetbrains.jet.lang.psi.JetFile;
+import org.jetbrains.jet.lang.psi.stubs.impl.PsiJetFileStubImpl;
+
+/**
+ * @author Nikolay Krasko
+ */
+public class JetFileStubBuilder extends DefaultStubBuilder {
+ @Override
+ protected StubElement createStubForFile(PsiFile file) {
+
+ if (!(file instanceof JetFile)) return super.createStubForFile(file);
+
+ JetFile jetFile = (JetFile) file;
+
+ // TODO (stubs):
+ String packageName = "default";
+
+// String refText = "";
+//
+// final LighterASTNode pkg = LightTreeUtil.firstChildOfType(tree, tree.getRoot(), JavaElementType.PACKAGE_STATEMENT);
+// if (pkg != null) {
+// final LighterASTNode ref = LightTreeUtil.firstChildOfType(tree, pkg, JavaElementType.JAVA_CODE_REFERENCE);
+// if (ref != null) {
+// refText = SourceUtil.getTextSkipWhiteSpaceAndComments(tree, ref);
+//
+// }
+// }
+
+ return new PsiJetFileStubImpl(jetFile, StringRef.fromString(packageName));
+ }
+}
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetFunctionElementType.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetFunctionElementType.java
new file mode 100644
index 00000000000..12f2eda3c83
--- /dev/null
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetFunctionElementType.java
@@ -0,0 +1,56 @@
+package org.jetbrains.jet.lang.psi.stubs.elements;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.lang.LighterAST;
+import com.intellij.lang.LighterASTNode;
+import com.intellij.psi.stubs.StubElement;
+import com.intellij.psi.stubs.StubInputStream;
+import com.intellij.psi.stubs.StubOutputStream;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jet.lang.psi.JetFunction;
+import org.jetbrains.jet.lang.psi.JetNamedFunction;
+import org.jetbrains.jet.lang.psi.stubs.PsiJetFunctionStub;
+import org.jetbrains.jet.plugin.JetLanguage;
+
+import java.io.IOException;
+
+/**
+ * @author Nikolay Krasko
+ */
+public abstract class JetFunctionElementType extends JetStubElementType {
+
+ public JetFunctionElementType(@NotNull @NonNls String debugName) {
+ super(debugName, JetLanguage.INSTANCE);
+ }
+
+ @Override
+ public JetFunction createPsiFromAst(@NotNull ASTNode node) {
+ return new JetNamedFunction(node);
+ }
+
+ @Override
+ public PsiJetFunctionStub createStub(LighterAST tree, LighterASTNode node, StubElement parentStub) {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public JetFunction createPsi(@NotNull PsiJetFunctionStub stub) {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public PsiJetFunctionStub createStub(@NotNull JetFunction psi, StubElement parentStub) {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public void serialize(PsiJetFunctionStub stub, StubOutputStream dataStream) throws IOException {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public PsiJetFunctionStub deserialize(StubInputStream dataStream, StubElement parentStub) throws IOException {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+}
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetStubElementFactory.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetStubElementFactory.java
new file mode 100644
index 00000000000..12674702df9
--- /dev/null
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetStubElementFactory.java
@@ -0,0 +1,9 @@
+package org.jetbrains.jet.lang.psi.stubs.elements;
+
+/**
+ * @author Nikolay Krasko
+ */
+public interface JetStubElementFactory {
+ JetClassElementType getClassElementType();
+ JetFunctionElementType getFunctionElementType();
+}
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetStubElementType.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetStubElementType.java
new file mode 100644
index 00000000000..3211f89feb3
--- /dev/null
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetStubElementType.java
@@ -0,0 +1,46 @@
+package org.jetbrains.jet.lang.psi.stubs.elements;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.lang.Language;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.impl.java.stubs.PsiJavaFileStub;
+import com.intellij.psi.impl.java.stubs.StubPsiFactory;
+import com.intellij.psi.stubs.ILightStubElementType;
+import com.intellij.psi.stubs.PsiFileStub;
+import com.intellij.psi.stubs.StubElement;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author Nikolay Krasko
+ */
+public abstract class JetStubElementType
+ extends ILightStubElementType {
+
+ public JetStubElementType(@NotNull @NonNls String debugName, @Nullable Language language) {
+ super(debugName, language);
+ }
+
+
+
+ public abstract PsiT createPsiFromAst(@NotNull ASTNode node);
+
+ protected StubPsiFactory getPsiFactory(StubT stub) {
+ return getFileStub(stub).getPsiFactory();
+ }
+
+ private PsiJavaFileStub getFileStub(StubT stub) {
+ StubElement parent = stub;
+ while (!(parent instanceof PsiFileStub)) {
+ parent = parent.getParentStub();
+ }
+
+ return (PsiJavaFileStub)parent;
+ }
+
+ @Override
+ public String getExternalId() {
+ return "jet." + toString();
+ }
+}
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetStubElementTypes.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetStubElementTypes.java
new file mode 100644
index 00000000000..e37bf075100
--- /dev/null
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/elements/JetStubElementTypes.java
@@ -0,0 +1,13 @@
+package org.jetbrains.jet.lang.psi.stubs.elements;
+
+import org.jetbrains.jet.lang.parsing.JetParserDefinition;
+
+/**
+ * @author Nikolay Krasko
+ */
+public interface JetStubElementTypes {
+ JetFileElementType FILE = new JetFileElementType();
+
+ JetClassElementType CLASS = JetParserDefinition.getStubElementTypeFactory().getClassElementType();
+ JetFunctionElementType FUNCTION = JetParserDefinition.getStubElementTypeFactory().getFunctionElementType();
+}
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/impl/PsiJetClassStubImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/impl/PsiJetClassStubImpl.java
new file mode 100644
index 00000000000..5a480366c00
--- /dev/null
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/impl/PsiJetClassStubImpl.java
@@ -0,0 +1,57 @@
+package org.jetbrains.jet.lang.psi.stubs.impl;
+
+import com.intellij.psi.stubs.StubBase;
+import com.intellij.psi.stubs.StubElement;
+import com.intellij.util.io.StringRef;
+import org.jetbrains.jet.lang.psi.JetClass;
+import org.jetbrains.jet.lang.psi.stubs.PsiJetClassStub;
+import org.jetbrains.jet.lang.psi.stubs.elements.JetClassElementType;
+
+/**
+ * @author Nikolay Krasko
+ */
+public class PsiJetClassStubImpl extends StubBase implements PsiJetClassStub {
+
+ private final StringRef qualifiedName;
+ private final StringRef name;
+
+ public PsiJetClassStubImpl(
+ JetClassElementType type,
+ final StubElement parent,
+ final String qualifiedName,
+ final String name) {
+
+ this(type, parent, StringRef.fromString(qualifiedName), StringRef.fromString(name));
+ }
+
+ public PsiJetClassStubImpl(
+ JetClassElementType type,
+ final StubElement parent,
+ final StringRef qualifiedName,
+ final StringRef name) {
+
+ super(parent, type);
+ this.qualifiedName = qualifiedName;
+ this.name = name;
+ }
+
+ @Override
+ public String getQualifiedName() {
+ return StringRef.toString(qualifiedName);
+ }
+
+ @Override
+ public boolean isDeprecated() {
+ return false;
+ }
+
+ @Override
+ public boolean hasDeprecatedAnnotation() {
+ return false;
+ }
+
+ @Override
+ public String getName() {
+ return StringRef.toString(name);
+ }
+}
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/impl/PsiJetFileStubImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/impl/PsiJetFileStubImpl.java
new file mode 100644
index 00000000000..78dfaa14b13
--- /dev/null
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/impl/PsiJetFileStubImpl.java
@@ -0,0 +1,43 @@
+package org.jetbrains.jet.lang.psi.stubs.impl;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.impl.java.stubs.StubPsiFactory;
+import com.intellij.psi.stubs.PsiFileStubImpl;
+import com.intellij.util.io.StringRef;
+import org.jetbrains.jet.lang.psi.JetFile;
+import org.jetbrains.jet.lang.psi.stubs.PsiJetFileStub;
+
+/**
+ * @author Nikolay Krasko
+ */
+public class PsiJetFileStubImpl extends PsiFileStubImpl implements PsiJetFileStub {
+
+ private final StringRef packageName;
+ private StubPsiFactory psiFactory;
+
+ public PsiJetFileStubImpl(JetFile jetFile, StringRef packageName) {
+ super(jetFile);
+
+ this.packageName = packageName;
+ }
+
+ @Override
+ public String getPackageName() {
+ return StringRef.toString(packageName);
+ }
+
+ @Override
+ public StubPsiFactory getPsiFactory() {
+ return psiFactory;
+ }
+
+ @Override
+ public void setPsiFactory(StubPsiFactory factory) {
+ psiFactory = factory;
+ }
+
+ @Override
+ public PsiClass[] getClasses() {
+ return new PsiClass[0]; //To change body of implemented methods use File | Settings | File Templates.
+ }
+}
diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/impl/PsiJetFunctionStubImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/impl/PsiJetFunctionStubImpl.java
new file mode 100644
index 00000000000..b8f580be58e
--- /dev/null
+++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/stubs/impl/PsiJetFunctionStubImpl.java
@@ -0,0 +1,59 @@
+package org.jetbrains.jet.lang.psi.stubs.impl;
+
+import com.intellij.psi.stubs.IStubElementType;
+import com.intellij.psi.stubs.StubBase;
+import com.intellij.psi.stubs.StubElement;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jet.lang.psi.JetFunction;
+import org.jetbrains.jet.lang.psi.stubs.PsiJetFunctionStub;
+
+/**
+ * @author Nikolay Krasko
+ */
+public class PsiJetFunctionStubImpl extends StubBase implements PsiJetFunctionStub {
+ protected PsiJetFunctionStubImpl(StubElement parent, IStubElementType elementType) {
+ super(parent, elementType);
+ }
+
+// public PsiJetFunctionStubImpl(
+// Jet type,
+// final StubElement parent,
+// final String qualifiedName,
+// final String name) {
+//
+// this(type, parent, StringRef.fromString(qualifiedName), StringRef.fromString(name));
+// }
+//
+// public PsiJetFunctionStubImpl(
+// JetClassElementType type,
+// final StubElement parent,
+// final StringRef qualifiedName,
+// final StringRef name) {
+//
+// super(parent, type);
+// this.qualifiedName = qualifiedName;
+// this.name = name;
+// }
+
+ @Override
+ public String getName() {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public boolean isDeclaration() {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @NotNull
+ @Override
+ public String[] getAnnotations() {
+ return new String[0]; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @NotNull
+ @Override
+ public String getReturnTypeText() {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+}
diff --git a/examples/example-vfs/example-vfs.iml b/examples/example-vfs/example-vfs.iml
new file mode 100644
index 00000000000..37bed8abc1d
--- /dev/null
+++ b/examples/example-vfs/example-vfs.iml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/example-vfs/example-vfs.ipr b/examples/example-vfs/example-vfs.ipr
new file mode 100644
index 00000000000..77f63b1e9c3
--- /dev/null
+++ b/examples/example-vfs/example-vfs.ipr
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+ http://www.w3.org/1999/xhtml
+
+
+
+
+
+
+
+
+
diff --git a/examples/example-vfs/src/FileSystem.kt b/examples/example-vfs/src/FileSystem.kt
new file mode 100644
index 00000000000..e9380227794
--- /dev/null
+++ b/examples/example-vfs/src/FileSystem.kt
@@ -0,0 +1,130 @@
+package org.jetbrains.jet.samples.vfs;
+
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import org.jetbrains.jet.samples.vfs.utils.*;
+import java.util.concurrent.locks.Lock
+import java.io.File
+import java.util.List
+import java.util.ArrayList
+import java.util.HashMap
+import java.util.Arrays
+import java.util.Map
+
+import std.util.*
+
+/**
+ * File system singleton. To work with virtual file system, read/write locks should be
+ * acquired: use read() and write() higher-order functions.
+ */
+public object FileSystem {
+ private val lock = ReentrantReadWriteLock()
+ internal val watchedDirectories = ArrayList
+
+ // FIXME VirtualFiles should be used as hashmap keys themselves,
+ // but overriden hashCode() method fails in runtime with ClassCastException (KT-1134)
+ /**
+ * Mapping from virtual files to metainformation
+ */
+ internal val fileToInfo = HashMap()
+ private val listeners = ArrayList()
+
+ /**
+ * Returns corresponding virtual file for java.io.File.
+ *
+ * @param ioFile file
+ */
+ public fun getFileByIoFile(ioFile : File) : VirtualFile {
+ FileSystem.assertCanRead()
+ return PhysicalVirtualFile(ioFile.getAbsolutePath().sure().toSystemIndependentPath())
+ }
+
+ /**
+ * Returns virtual file for path to it.
+ *
+ * @param path path to file
+ */
+ public fun getFileByPath(path : String) : VirtualFile {
+ return getFileByIoFile(File(path))
+ }
+
+ /**
+ * Runs function with read lock.
+ */
+ public inline fun read(task : () -> T) : T {
+ return locked(lock.readLock().sure(), task)
+ }
+
+ /**
+ * Runs function with write lock.
+ */
+ public inline fun write(task : () -> T) : T {
+ return locked(lock.writeLock().sure(), task)
+ }
+
+ /**
+ * Adds directory to list of watched directories. Watched directories are
+ * periodically refreshed and corresponding events are sent to file system listeners.
+ *
+ * @param dir directory which should be watched
+ */
+ public fun addWatchedDirectory(dir : VirtualFile) {
+ assertCanRead()
+ if (dir.isDirectory()) {
+ watchedDirectories.add(dir)
+ scanAndAddRecursivelyNoEvents(dir)
+
+ RefreshQueue.scheduleRefresh()
+ }
+ }
+
+ /* Scans file recursively and adds info about it to fileToInfo map */
+ private fun scanAndAddRecursivelyNoEvents(file : VirtualFile) {
+ assert(FileSystem.fileToInfo[file.path] == null)
+
+ val fileInfo = VirtualFileInfo(file)
+ FileSystem.fileToInfo[file.path] = fileInfo
+ fileInfo.children.foreach{ scanAndAddRecursivelyNoEvents(it) }
+ }
+
+ internal inline fun assertCanRead() {
+ assert(lock.getReadHoldCount() != 0 || lock.isWriteLockedByCurrentThread())
+ }
+
+ internal inline fun assertCanWrite() {
+ assert(lock.isWriteLockedByCurrentThread())
+ }
+
+ /**
+ * Adds file system listener which should be notified about changing of file system.
+ */
+ public fun addVirtualFileListener(listener : VirtualFileListener) {
+ listeners.add(listener)
+ }
+
+ /**
+ * Removes file system listener.
+ */
+ public fun removeVirtualFileListener(listener : VirtualFileListener) {
+ listeners.remove(listener)
+ }
+
+ /* Notifies all listeners */
+ internal fun notifyEventHappened(event : VirtualFileEvent) {
+ for (listener in listeners) {
+ listener.eventHappened(event)
+ }
+ }
+}
+
+private class VirtualFileInfo(file : VirtualFile) {
+ /* Last modification time */
+ var lastModified : Long = 0
+ /* List of known children */
+ val children : List = ArrayList;
+
+ {
+ children.addAll(file.children())
+ lastModified = file.modificationTime()
+ }
+}
diff --git a/examples/example-vfs/src/Main.kt b/examples/example-vfs/src/Main.kt
new file mode 100644
index 00000000000..7c288a228b2
--- /dev/null
+++ b/examples/example-vfs/src/Main.kt
@@ -0,0 +1,36 @@
+package org.jetbrains.jet.samples.vfs.sandbox;
+
+import org.jetbrains.jet.samples.vfs.*;
+import java.io.InputStreamReader
+import java.util.Scanner
+
+/**
+ * Receives list of directories which should be watched, adds them to virtual file system,
+ * adds virtual file system listener and waits for 1 minutes, printing out all received event.
+ */
+fun main(args : Array) {
+ if (args.size == 0) {
+ println("Provide list of watched directories as command line arguments")
+ return
+ }
+
+ // add watched directory
+ FileSystem.write {
+ for (val arg in args) {
+ FileSystem.addWatchedDirectory(FileSystem.getFileByPath(arg))
+ }
+ }
+
+ // add listener which prints out everything
+ FileSystem.addVirtualFileListener(object : VirtualFileListener {
+ override fun eventHappened(event: VirtualFileEvent) {
+ println(event)
+ if (event is VirtualFileChangedEvent) {
+ println("new file size is ${event.file.size()}")
+ }
+ }
+ })
+
+ // wait for 1 minute
+ Thread.sleep(60000)
+}
\ No newline at end of file
diff --git a/examples/example-vfs/src/RefreshQueue.kt b/examples/example-vfs/src/RefreshQueue.kt
new file mode 100644
index 00000000000..09e7f21713f
--- /dev/null
+++ b/examples/example-vfs/src/RefreshQueue.kt
@@ -0,0 +1,138 @@
+package org.jetbrains.jet.samples.vfs;
+
+import java.util.concurrent.ConcurrentLinkedQueue
+import java.util.List
+import java.util.concurrent.locks.ReentrantLock
+import java.util.concurrent.LinkedBlockingQueue
+import java.util.ArrayList
+
+import std.util.*
+import java.util.Timer
+import java.util.TimerTask
+
+import org.jetbrains.jet.samples.vfs.utils.*
+
+/**
+ * Singleton which creates thread for periodically checking if there are changes in
+ * file system and notifying file system listeners.
+ */
+internal object RefreshQueue : Runnable {
+ private val taskQueue = LinkedBlockingQueue>()
+ private val workerThread: Thread = Thread(this)
+ private val fullRefreshScheduler = Timer(true);
+
+ {
+ workerThread.setDaemon(true)
+ workerThread.start()
+
+ fullRefreshScheduler.scheduleAtFixedRate(createTimerTask {
+ scheduleRefresh(FileSystem.watchedDirectories)
+ }, 0, 5000)
+ }
+
+ private fun takeAndRefreshFiles() {
+ refreshFiles(taskQueue.take())
+ }
+
+ /* Acquires write lock and refreshes file system */
+ private fun refreshFiles(files : List) {
+ FileSystem.write {
+ files.foreach{ refreshFile(it) }
+ }
+ }
+
+ /* Checks for changes in virtual file recursively, notifying listeners. */
+ private fun refreshFile(file : VirtualFile) {
+ FileSystem.assertCanWrite()
+ if (file.isDirectory()) {
+ val fileToInfo = FileSystem.fileToInfo
+ val fileInfo = fileToInfo[file.path]
+ val oldChildren = fileInfo.children
+ val newChildren = file.children()
+
+ val addedChildren = listDifference(newChildren, oldChildren)
+ val deletedChildren = listDifference(oldChildren, newChildren)
+ val commonChildren = listIntersection(oldChildren, newChildren)
+
+ addedChildren.foreach{ addRecursively(it) }
+ deletedChildren.foreach{ deleteRecursively(it) }
+
+ fileInfo.children.clear()
+ fileInfo.children.addAll(newChildren)
+
+ commonChildren.foreach{ refreshFile(it) }
+ } else {
+ val fileInfo = FileSystem.fileToInfo[file.path]
+ assert(fileInfo != null)
+
+ val newModificationTime = file.modificationTime()
+ if (fileInfo.lastModified != newModificationTime) {
+ fileInfo.lastModified = newModificationTime
+
+ FileSystem.notifyEventHappened(VirtualFileChangedEvent(file))
+ }
+ }
+ }
+
+ /* Adds file to file system recursively, notifying listeners */
+ private fun addRecursively(file : VirtualFile) {
+ assert(FileSystem.fileToInfo[file] == null)
+
+ val fileInfo = VirtualFileInfo(file)
+
+ FileSystem.fileToInfo[file.path] = fileInfo
+ FileSystem.notifyEventHappened(VirtualFileCreateEvent(file))
+
+ fileInfo.children.foreach{ addRecursively(it) }
+ }
+
+ /* Deletes file from file system recursively, notifying listeners */
+ private fun deleteRecursively(file : VirtualFile) {
+ val fileInfoMaybe : VirtualFileInfo? = FileSystem.fileToInfo[file.path]
+ val fileInfo = fileInfoMaybe.sure()
+ fileInfo.children.foreach{ deleteRecursively(it) }
+ FileSystem.notifyEventHappened(VirtualFileDeletedEvent(file))
+ FileSystem.fileToInfo.remove(file)
+ }
+
+ /**
+ * Schedules refresh for given list of files.
+ */
+ public fun scheduleRefresh(files : List) {
+ taskQueue.put(files)
+ }
+
+ /**
+ * Schedules refresh for given list of files.
+ */
+ public fun scheduleRefresh(vararg files : VirtualFile) {
+ // FIXME This could be written more concise, using map() & toList() (KT-1164 & KT-1172)
+ val filesList = ArrayList()
+ files.foreach{ filesList.add(it) }
+ taskQueue.put(filesList)
+
+ // taskQueue.put(ArrayList(files.map{ it }))
+ // taskQueue.put(files.map{ it }.toList())
+ }
+
+ // FIXME RefreshQueue implements Runnable because of error on accessing
+ // private fields and methods from anonymous class (KT-1157 & KT-1159) (
+ override fun run() {
+ while (!workerThread.isInterrupted()) {
+ try {
+ takeAndRefreshFiles()
+ } catch (e : InterruptedException) {
+ }
+ }
+ }
+}
+
+// FIXME this method is used because of error on accessing
+// private methods from anonymous class (KT-1157) (
+private fun createTimerTask(task : () -> Unit) : TimerTask {
+ return object : TimerTask() {
+ override fun run() {
+ task()
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/example-vfs/src/Utils.kt b/examples/example-vfs/src/Utils.kt
new file mode 100644
index 00000000000..7926599c927
--- /dev/null
+++ b/examples/example-vfs/src/Utils.kt
@@ -0,0 +1,42 @@
+package org.jetbrains.jet.samples.vfs.utils;
+
+import java.util.concurrent.locks.Lock
+import java.util.List
+import std.util.*
+
+/**
+ * Executes task with given lock acquired.
+ */
+private fun locked(lock : Lock, body : () -> T) : T {
+ lock.lock()
+ try {
+ return body()
+ } finally {
+ lock.unlock();
+ }
+}
+
+/**
+ * Checks boolean value which should be true. If it is false, throws Assertion Error
+ *
+ * @param value value to be checked
+ */
+public fun assert(value : Boolean) {
+ if (!value) {
+ throw AssertionError()
+ }
+}
+
+/**
+ * Returns list containing all elements which first contains and second does not.
+ */
+public fun listDifference(first : List, second : List) : List {
+ return first.filter{ !second.contains(it) }.toList()
+}
+
+/**
+ * Returns list containing all elements which both lists contain.
+ */
+public fun listIntersection(first : List, second : List) : List {
+ return first.filter{ second.contains(it) }.toList()
+}
diff --git a/examples/example-vfs/src/VirtualFile.kt b/examples/example-vfs/src/VirtualFile.kt
new file mode 100644
index 00000000000..f848cedf4c7
--- /dev/null
+++ b/examples/example-vfs/src/VirtualFile.kt
@@ -0,0 +1,164 @@
+package org.jetbrains.jet.samples.vfs;
+
+import org.jetbrains.jet.samples.vfs.utils.*;
+import java.io.File
+import java.io.InputStream
+import java.io.FileInputStream
+import java.util.ArrayList
+import java.util.List
+
+import std.util.*
+
+/**
+ * Abstract virtual file.
+ */
+public abstract class VirtualFile(public val path : String) {
+ // FIXME this method should be replaced with val (KT-1168, KT-1170)
+ protected abstract fun kind() : String
+
+ // FIXME these abstract methods should be replaced with vals (KT-1165)
+ /**
+ * Returns file size.
+ */
+ public abstract fun size() : Long
+ /**
+ * Returns the time that the virtual file was last modified (milliseconds since
+ * the epoch (00:00:00 GMT, January 1, 1970).
+ */
+ public abstract fun modificationTime() : Long
+ /**
+ * Returns if virtual file exists.
+ */
+ public abstract fun exists() : Boolean
+ /**
+ * Returns if virtual file is directory
+ */
+ public abstract fun isDirectory() : Boolean
+ /**
+ * Returns list of virtual files which are children for this.
+ */
+ public abstract fun children() : List
+
+ /**
+ * Opens input stream for reading. After reading, stream should be closed.
+ * Reading from stream should be performed with read lock acquired.
+ */
+ public abstract fun openInputStream() : InputStream
+
+ fun equals(other : Any?) : Boolean {
+ return other is VirtualFile && kind() == other.kind() && path == other.path
+ }
+
+ fun hashCode() : Int {
+ // FIXME rewrite without casting when it will be possible
+ return (kind() as java.lang.String).hashCode() * 31 + (path as java.lang.String).hashCode()
+ }
+
+ fun toString(): String {
+ return "${kind()}[path=$path]"
+ }
+}
+
+/**
+ * Type of virtual file which corresponds to real file in file system of OS.
+ */
+public class PhysicalVirtualFile(path : String) : VirtualFile(path) {
+ override fun kind() : String = "Physical"
+
+ private val ioFile : File
+ get() = File(this.path.toSystemDependentPath())
+
+ override fun exists(): Boolean {
+ FileSystem.assertCanRead()
+ return ioFile.exists()
+ }
+
+ override fun size(): Long {
+ FileSystem.assertCanRead()
+ return ioFile.length()
+ }
+
+ override fun modificationTime(): Long {
+ FileSystem.assertCanRead()
+ return ioFile.lastModified()
+ }
+
+ override fun isDirectory(): Boolean {
+ FileSystem.assertCanRead()
+ return ioFile.isDirectory()
+ }
+
+ override fun children(): List {
+ FileSystem.assertCanRead()
+ return (ioFile.listFiles() ?: Array(0)).
+ map{ FileSystem.getFileByIoFile(it.sure()) }?.toList()
+ }
+
+ override fun openInputStream(): InputStream {
+ FileSystem.assertCanRead()
+ if (isDirectory()) {
+ throw IllegalArgumentException("Can't open directory for reading");
+ }
+ return CheckedInputStream(FileInputStream(ioFile))
+ }
+}
+
+private fun String.toSystemDependentPath() : String {
+ // FIXME constants should be extracted (NPE in compiler, KT-1111)
+ return this.replaceAll("/", java.io.File.separator.sure())
+}
+
+private fun String.toSystemIndependentPath() : String {
+ // FIXME constants should be extracted (NPE in compiler, KT-1111)
+ return this.replaceAll(java.io.File.separator.sure(), "/")
+}
+
+/**
+ * InputStream wrapper which checks that file system read lock is acquired on each operation.
+ */
+private class CheckedInputStream(private val wrapped : InputStream) : InputStream() {
+ override fun read(): Int {
+ FileSystem.assertCanRead()
+ return wrapped.read()
+ }
+
+ override fun read(b: ByteArray?, off: Int, len: Int) : Int {
+ FileSystem.assertCanRead()
+ return wrapped.read(b, off, len)
+ }
+
+ override fun markSupported(): Boolean {
+ FileSystem.assertCanRead()
+ return wrapped.markSupported()
+ }
+
+ override fun skip(n: Long): Long {
+ FileSystem.assertCanRead()
+ return wrapped.skip(n)
+ }
+
+ override fun close() {
+ FileSystem.assertCanRead()
+ return wrapped.close()
+ }
+
+ override fun mark(readlimit: Int) {
+ FileSystem.assertCanRead()
+ return wrapped.mark(readlimit)
+ }
+
+ override fun read(b: ByteArray?): Int {
+ FileSystem.assertCanRead()
+ return wrapped.read(b)
+ }
+
+ override fun reset() {
+ FileSystem.assertCanRead()
+ return wrapped.reset()
+ }
+
+ override fun available(): Int {
+ FileSystem.assertCanRead()
+ return wrapped.available()
+ }
+}
\ No newline at end of file
diff --git a/examples/example-vfs/src/VirtualFileEvent.kt b/examples/example-vfs/src/VirtualFileEvent.kt
new file mode 100644
index 00000000000..7f3d043a5c4
--- /dev/null
+++ b/examples/example-vfs/src/VirtualFileEvent.kt
@@ -0,0 +1,42 @@
+package org.jetbrains.jet.samples.vfs;
+
+/**
+ * Listener for receiving virtual file event
+ */
+public trait VirtualFileListener : java.util.EventListener {
+ fun eventHappened(val event : VirtualFileEvent)
+}
+
+/**
+ * Base type of virtual file events
+ * @property file affected by event
+ */
+public abstract class VirtualFileEvent(val file : VirtualFile) : Object() {
+}
+
+/**
+ * Event of creating file
+ */
+public class VirtualFileCreateEvent(file : VirtualFile) : VirtualFileEvent(file) {
+ override fun toString(): String? {
+ return "created ${file}"
+ }
+}
+
+/**
+ * Event of deleting file
+ */
+public class VirtualFileDeletedEvent(file : VirtualFile) : VirtualFileEvent(file) {
+ override fun toString(): String? {
+ return "deleted ${file}"
+ }
+}
+
+/**
+ * Event of changing file contents
+ */
+public class VirtualFileChangedEvent(file : VirtualFile) : VirtualFileEvent(file) {
+ override fun toString(): String? {
+ return "changed ${file}"
+ }
+}
diff --git a/idea/src/org/jetbrains/jet/plugin/ParserConfigurator.java b/idea/src/org/jetbrains/jet/plugin/ParserConfigurator.java
new file mode 100644
index 00000000000..36eb6db31d4
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/ParserConfigurator.java
@@ -0,0 +1,15 @@
+package org.jetbrains.jet.plugin;
+
+/**
+ * Configures jet parser for using indexed stubs instead of default set.
+ * So if parser is used from IDEA it creates indexed stubs, if not direct psi elements are used.
+ *
+ * IMPORTANT: Should be called before loading parser.
+ *
+ * @author Nikolay Krasko
+ */
+public class ParserConfigurator {
+// static {
+// JetParserDefinition.setStubFactory(new JetIndexedStubElementFactory());
+// }
+}
diff --git a/idea/src/org/jetbrains/jet/plugin/stubindex/JetFullClassNameIndex.java b/idea/src/org/jetbrains/jet/plugin/stubindex/JetFullClassNameIndex.java
new file mode 100644
index 00000000000..5f17ff4459d
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/stubindex/JetFullClassNameIndex.java
@@ -0,0 +1,31 @@
+package org.jetbrains.jet.plugin.stubindex;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.stubs.StringStubIndexExtension;
+import com.intellij.psi.stubs.StubIndexKey;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jet.lang.psi.JetClassOrObject;
+
+import java.util.Collection;
+
+/**
+ * @author Nikolay Krasko
+ */
+public class JetFullClassNameIndex extends StringStubIndexExtension {
+
+ private static final JetFullClassNameIndex ourInstance = new JetFullClassNameIndex();
+ public static JetFullClassNameIndex getInstance() {
+ return ourInstance;
+ }
+
+ @Override
+ public StubIndexKey getKey() {
+ return JetIndexKeys.FQN_KEY;
+ }
+
+ @Override
+ public Collection get(final String integer, final Project project, @NotNull final GlobalSearchScope scope) {
+ return super.get(integer, project, new JetSourceFilterScope(scope));
+ }
+}
diff --git a/idea/src/org/jetbrains/jet/plugin/stubindex/JetIndexKeys.java b/idea/src/org/jetbrains/jet/plugin/stubindex/JetIndexKeys.java
new file mode 100644
index 00000000000..fed0fe7e5c8
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/stubindex/JetIndexKeys.java
@@ -0,0 +1,20 @@
+package org.jetbrains.jet.plugin.stubindex;
+
+import com.intellij.psi.stubs.StubIndexKey;
+import org.jetbrains.jet.lang.psi.JetClassOrObject;
+import org.jetbrains.jet.lang.psi.JetFunction;
+
+/**
+ * @author Nikolay Krasko
+ */
+public interface JetIndexKeys {
+ StubIndexKey SHORT_NAME_KEY = StubIndexKey.createIndexKey("jet.class.shortName");
+ StubIndexKey FQN_KEY = StubIndexKey.createIndexKey("jet.fqn");
+
+ StubIndexKey TOP_LEVEL_FUNCTION_SHORT_NAME_KEY = StubIndexKey.createIndexKey("jet.top.level.function.short.name");
+// StubIndexKey TOP_LEVEL_FUNCTION_FQN_KEY = StubIndexKey.createIndexKey("jet.top.level.function.short.name");
+
+// StubIndexKey PACKAGE_OBJECT_KEY = StubIndexKey.createIndexKey("jet.package.object.fqn");
+// StubIndexKey EXTENSION_FUNCTION_TO_TYPE_FQN = StubIndexKey.createIndexKey("jet.extension.function.to.type.fqn");
+}
+
diff --git a/idea/src/org/jetbrains/jet/plugin/stubindex/JetIndexedStubElementFactory.java b/idea/src/org/jetbrains/jet/plugin/stubindex/JetIndexedStubElementFactory.java
new file mode 100644
index 00000000000..773389dc288
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/stubindex/JetIndexedStubElementFactory.java
@@ -0,0 +1,40 @@
+package org.jetbrains.jet.plugin.stubindex;
+
+import com.intellij.psi.stubs.IndexSink;
+import org.jetbrains.jet.lang.psi.stubs.PsiJetClassStub;
+import org.jetbrains.jet.lang.psi.stubs.PsiJetFunctionStub;
+import org.jetbrains.jet.lang.psi.stubs.elements.JetClassElementType;
+import org.jetbrains.jet.lang.psi.stubs.elements.JetFunctionElementType;
+import org.jetbrains.jet.lang.psi.stubs.elements.JetStubElementFactory;
+
+/**
+ * @author Nikolay Krasko
+ */
+public class JetIndexedStubElementFactory implements JetStubElementFactory {
+ @Override
+ public JetClassElementType getClassElementType() {
+ return new JetClassElementType("CLASS") {
+ @Override
+ public void indexStub(PsiJetClassStub stub, IndexSink sink) {
+ String name = stub.getName();
+ if (name != null) {
+ sink.occurrence(JetIndexKeys.SHORT_NAME_KEY, name);
+ }
+ }
+ };
+ }
+
+ @Override
+ public JetFunctionElementType getFunctionElementType() {
+ return new JetFunctionElementType("FUN") {
+ @Override
+ public void indexStub(PsiJetFunctionStub stub, IndexSink sink) {
+ String name = stub.getName();
+ // TODO: Check that function defined in top level
+ if (name != null) {
+ sink.occurrence(JetIndexKeys.TOP_LEVEL_FUNCTION_SHORT_NAME_KEY, name);
+ }
+ }
+ };
+ }
+}
diff --git a/idea/src/org/jetbrains/jet/plugin/stubindex/JetShortClassNameIndex.java b/idea/src/org/jetbrains/jet/plugin/stubindex/JetShortClassNameIndex.java
new file mode 100644
index 00000000000..60afb4e5db2
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/stubindex/JetShortClassNameIndex.java
@@ -0,0 +1,30 @@
+package org.jetbrains.jet.plugin.stubindex;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.stubs.StringStubIndexExtension;
+import com.intellij.psi.stubs.StubIndexKey;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jet.lang.psi.JetClassOrObject;
+
+import java.util.Collection;
+
+/**
+ * @author Nikolay Krasko
+ */
+public class JetShortClassNameIndex extends StringStubIndexExtension {
+ private static final JetShortClassNameIndex ourInstance = new JetShortClassNameIndex();
+ public static JetShortClassNameIndex getInstance() {
+ return ourInstance;
+ }
+
+ @Override
+ public StubIndexKey getKey() {
+ return JetIndexKeys.SHORT_NAME_KEY;
+ }
+
+ @Override
+ public Collection get(final String s, final Project project, @NotNull final GlobalSearchScope scope) {
+ return super.get(s, project, new JetSourceFilterScope(scope));
+ }
+}
diff --git a/idea/src/org/jetbrains/jet/plugin/stubindex/JetShortFunctionNameIndex.java b/idea/src/org/jetbrains/jet/plugin/stubindex/JetShortFunctionNameIndex.java
new file mode 100644
index 00000000000..bb167dfc667
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/stubindex/JetShortFunctionNameIndex.java
@@ -0,0 +1,31 @@
+package org.jetbrains.jet.plugin.stubindex;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.stubs.StringStubIndexExtension;
+import com.intellij.psi.stubs.StubIndexKey;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jet.lang.psi.JetFunction;
+
+import java.util.Collection;
+
+/**
+ * @author Nikolay Krasko
+ */
+public class JetShortFunctionNameIndex extends StringStubIndexExtension {
+ private static final JetShortClassNameIndex ourInstance = new JetShortClassNameIndex();
+
+ public static JetShortClassNameIndex getInstance() {
+ return ourInstance;
+ }
+
+ @Override
+ public StubIndexKey getKey() {
+ return JetIndexKeys.TOP_LEVEL_FUNCTION_SHORT_NAME_KEY;
+ }
+
+ @Override
+ public Collection get(final String s, final Project project, @NotNull final GlobalSearchScope scope) {
+ return super.get(s, project, new JetSourceFilterScope(scope));
+ }
+}
diff --git a/idea/src/org/jetbrains/jet/plugin/stubindex/JetSourceFilterScope.java b/idea/src/org/jetbrains/jet/plugin/stubindex/JetSourceFilterScope.java
new file mode 100644
index 00000000000..45a65a6573a
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/stubindex/JetSourceFilterScope.java
@@ -0,0 +1,34 @@
+package org.jetbrains.jet.plugin.stubindex;
+
+import com.intellij.openapi.fileTypes.StdFileTypes;
+import com.intellij.openapi.roots.ProjectFileIndex;
+import com.intellij.openapi.roots.ProjectRootManager;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.search.DelegatingGlobalSearchScope;
+import com.intellij.psi.search.GlobalSearchScope;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Nikolay Krasko
+ */
+public class JetSourceFilterScope extends DelegatingGlobalSearchScope {
+ private final ProjectFileIndex myIndex;
+
+ public JetSourceFilterScope(@NotNull final GlobalSearchScope delegate) {
+ super(delegate);
+ myIndex = ProjectRootManager.getInstance(getProject()).getFileIndex();
+ }
+
+ @Override
+ public boolean contains(final VirtualFile file) {
+ if (!super.contains(file)) {
+ return false;
+ }
+
+ if (StdFileTypes.CLASS == file.getFileType()) {
+ return myIndex.isInLibraryClasses(file);
+ }
+
+ return myIndex.isInSourceContent(file);
+ }
+}