parse kotlin scripts

http://confluence.jetbrains.net/display/~stepan.koltsov/REPL
This commit is contained in:
Stepan Koltsov
2012-05-23 02:52:29 +04:00
parent a8bf3b6e10
commit 5fc73a4cd4
16 changed files with 275 additions and 4 deletions
@@ -27,6 +27,7 @@ import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.asJava.JavaElementFinder;
import org.jetbrains.jet.lang.parsing.JetParser;
import org.jetbrains.jet.lang.parsing.JetParserDefinition;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.java.CompilerDependencies;
@@ -68,6 +69,7 @@ public class JetCoreEnvironment extends JavaCoreEnvironment {
registerFileType(JetFileType.INSTANCE, "kt");
registerFileType(JetFileType.INSTANCE, "kts");
registerFileType(JetFileType.INSTANCE, "ktm");
registerFileType(JetFileType.INSTANCE, JetParser.KTSCRIPT_FILE_SUFFIX); // should be renamed to kts
registerFileType(JetFileType.INSTANCE, "jet");
registerParserDefinition(new JavaParserDefinition());
registerParserDefinition(new JetParserDefinition());
@@ -161,6 +161,7 @@ public interface JetNodeTypes {
JetNodeType WHEN_CONDITION_EXPRESSION = new JetNodeType("WHEN_CONDITION_WITH_EXPRESSION", JetWhenConditionWithExpression.class);
JetNodeType NAMESPACE_HEADER = new JetNodeType("NAMESPACE_HEADER", JetNamespaceHeader.class);
JetNodeType SCRIPT = new JetNodeType("SCRIPT", JetScript.class);
JetNodeType IDE_TEMPLATE_EXPRESSION = new JetNodeType("IDE_TEMPLATE_EXPRESSION", JetIdeTemplateExpression.class);
}
@@ -22,14 +22,30 @@ package org.jetbrains.jet.lang.parsing;
import com.intellij.lang.ASTNode;
import com.intellij.lang.PsiBuilder;
import com.intellij.lang.PsiParser;
import com.intellij.psi.PsiFile;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
public class JetParser implements PsiParser {
public static final String KTSCRIPT_FILE_SUFFIX = "ktscript";
@Override
@NotNull
public ASTNode parse(IElementType iElementType, PsiBuilder psiBuilder) {
JetParsing.createForTopLevel(new SemanticWhitespaceAwarePsiBuilderImpl(psiBuilder)).parseFile();
throw new IllegalStateException("use another parse");
}
// we need this method because we need psiFile
@NotNull
public ASTNode parse(IElementType iElementType, PsiBuilder psiBuilder, PsiFile psiFile) {
JetParsing jetParsing = JetParsing.createForTopLevel(new SemanticWhitespaceAwarePsiBuilderImpl(psiBuilder));
if (psiFile.getName().endsWith("." + KTSCRIPT_FILE_SUFFIX)) {
jetParsing.parseScript();
}
else {
jetParsing.parseFile();
}
return psiBuilder.getTreeBuilt();
}
}
@@ -104,6 +104,18 @@ public class JetParsing extends AbstractJetParsing {
fileMarker.done(JET_FILE);
}
void parseScript() {
PsiBuilder.Marker fileMarker = mark();
PsiBuilder.Marker scriptMarker = mark();
PsiBuilder.Marker blockMarker = mark();
myExpressionParsing.parseStatements();
blockMarker.done(BLOCK);
scriptMarker.done(SCRIPT);
fileMarker.done(JET_FILE);
}
/*
* toplevelObject[| import]*
*/
@@ -20,6 +20,7 @@
package org.jetbrains.jet.lang.psi;
import com.intellij.extapi.psi.PsiFileBase;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.psi.FileViewProvider;
import com.intellij.psi.PsiElementVisitor;
@@ -27,6 +28,7 @@ import com.intellij.psi.stubs.StubElement;
import com.intellij.psi.stubs.StubTree;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes;
import org.jetbrains.jet.plugin.JetFileType;
import org.jetbrains.jet.plugin.JetLanguage;
@@ -59,9 +61,20 @@ public class JetFile extends PsiFileBase implements JetDeclarationContainer {
return PsiTreeUtil.getChildrenOfTypeAsList(this, JetImportDirective.class);
}
@NotNull
// scripts has no namespace header
@Nullable
public JetNamespaceHeader getNamespaceHeader() {
return (JetNamespaceHeader) getNode().findChildByType(JetNodeTypes.NAMESPACE_HEADER).getPsi();
ASTNode ast = getNode().findChildByType(JetNodeTypes.NAMESPACE_HEADER);
return ast != null ? (JetNamespaceHeader) ast.getPsi() : null;
}
@Nullable
public JetScript getScript() {
return PsiTreeUtil.getChildOfType(this, JetScript.class);
}
public boolean isScript() {
return getScript() != null;
}
@NotNull
@@ -83,6 +83,10 @@ public class JetNamedFunction extends JetFunction implements StubBasedPsiElement
PsiElement parent = getParent();
if (parent instanceof JetFile) {
// fqname is different in scripts
if (((JetFile) parent).getNamespaceHeader() == null) {
return null;
}
JetFile jetFile = (JetFile) parent;
final FqName fileFQN = JetPsiUtil.getFQName(jetFile);
return fileFQN.child(getName());
@@ -0,0 +1,45 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.lang.psi;
import com.intellij.lang.ASTNode;
import org.jetbrains.annotations.NotNull;
/**
* @author Stepan Koltsov
*/
public class JetScript extends JetDeclaration {
public JetScript(@NotNull ASTNode node) {
super(node);
}
@NotNull
public JetBlockExpression getBlockExpression() {
return findNotNullChildByClass(JetBlockExpression.class);
}
@Override
public void accept(@NotNull JetVisitorVoid visitor) {
visitor.visitScript(this);
}
@Override
public <R, D> R accept(@NotNull JetVisitor<R, D> visitor, D data) {
return visitor.visitScript(this, data);
}
}
@@ -60,6 +60,10 @@ public class JetVisitor<R, D> extends PsiElementVisitor {
return null;
}
public R visitScript(JetScript script, D data) {
return visitDeclaration(script, data);
}
public R visitImportDirective(JetImportDirective importDirective, D data) {
return visitJetElement(importDirective, data);
}
@@ -58,6 +58,10 @@ public class JetVisitorVoid extends PsiElementVisitor {
visitFile(file);
}
public void visitScript(JetScript script) {
visitDeclaration(script);
}
public void visitImportDirective(JetImportDirective importDirective) {
visitJetElement(importDirective);
}
@@ -16,6 +16,14 @@
package org.jetbrains.jet.lang.psi.stubs.elements;
import com.intellij.lang.ASTNode;
import com.intellij.lang.Language;
import com.intellij.lang.LanguageParserDefinitions;
import com.intellij.lang.PsiBuilder;
import com.intellij.lang.PsiBuilderFactory;
import com.intellij.lang.PsiParser;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.StubBuilder;
import com.intellij.psi.stubs.IndexSink;
import com.intellij.psi.stubs.StubElement;
@@ -23,6 +31,8 @@ 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.annotations.NotNull;
import org.jetbrains.jet.lang.parsing.JetParser;
import org.jetbrains.jet.lang.psi.stubs.PsiJetFileStub;
import org.jetbrains.jet.lang.psi.stubs.impl.PsiJetFileStubImpl;
import org.jetbrains.jet.plugin.JetLanguage;
@@ -66,6 +76,15 @@ public class JetFileElementType extends IStubFileElementType<PsiJetFileStub> {
return new PsiJetFileStubImpl(null, packName);
}
protected ASTNode doParseContents(@NotNull final ASTNode chameleon, @NotNull final PsiElement psi) {
final Project project = psi.getProject();
Language languageForParser = getLanguageForParser(psi);
final PsiBuilder builder = PsiBuilderFactory.getInstance().createBuilder(project, chameleon, null, languageForParser, chameleon.getChars());
final JetParser parser = (JetParser) LanguageParserDefinitions.INSTANCE.forLanguage(languageForParser).createParser(project);
return parser.parse(this, builder, psi.getContainingFile()).getFirstChildNode();
}
@Override
public void indexStub(final PsiJetFileStub stub, final IndexSink sink) {
// Don't index file
@@ -0,0 +1,12 @@
fun die(message: String) {
System.err.println(message)
System.exit(1)
}
if (args.length == 0) {
die("Need arguments")
}
for (arg in args) {
println(arg)
}
@@ -0,0 +1,124 @@
JetFile: ComplexScript.ktscript
SCRIPT
BLOCK
FUN
PsiElement(fun)('fun')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('die')
VALUE_PARAMETER_LIST
PsiElement(LPAR)('(')
VALUE_PARAMETER
PsiElement(IDENTIFIER)('message')
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('String')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
BLOCK
PsiElement(LBRACE)('{')
PsiWhiteSpace('\n ')
DOT_QUALIFIED_EXPRESSION
DOT_QUALIFIED_EXPRESSION
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('System')
PsiElement(DOT)('.')
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('err')
PsiElement(DOT)('.')
CALL_EXPRESSION
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('println')
VALUE_ARGUMENT_LIST
PsiElement(LPAR)('(')
VALUE_ARGUMENT
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('message')
PsiElement(RPAR)(')')
PsiWhiteSpace('\n ')
DOT_QUALIFIED_EXPRESSION
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('System')
PsiElement(DOT)('.')
CALL_EXPRESSION
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('exit')
VALUE_ARGUMENT_LIST
PsiElement(LPAR)('(')
VALUE_ARGUMENT
INTEGER_CONSTANT
PsiElement(INTEGER_LITERAL)('1')
PsiElement(RPAR)(')')
PsiWhiteSpace('\n')
PsiElement(RBRACE)('}')
PsiWhiteSpace('\n\n')
IF
PsiElement(if)('if')
PsiWhiteSpace(' ')
PsiElement(LPAR)('(')
CONDITION
BINARY_EXPRESSION
DOT_QUALIFIED_EXPRESSION
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('args')
PsiElement(DOT)('.')
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('length')
PsiWhiteSpace(' ')
OPERATION_REFERENCE
PsiElement(EQEQ)('==')
PsiWhiteSpace(' ')
INTEGER_CONSTANT
PsiElement(INTEGER_LITERAL)('0')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
THEN
BLOCK
PsiElement(LBRACE)('{')
PsiWhiteSpace('\n ')
CALL_EXPRESSION
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('die')
VALUE_ARGUMENT_LIST
PsiElement(LPAR)('(')
VALUE_ARGUMENT
STRING_TEMPLATE
PsiElement(OPEN_QUOTE)('"')
LITERAL_STRING_TEMPLATE_ENTRY
PsiElement(REGULAR_STRING_PART)('Need arguments')
PsiElement(CLOSING_QUOTE)('"')
PsiElement(RPAR)(')')
PsiWhiteSpace('\n')
PsiElement(RBRACE)('}')
PsiWhiteSpace('\n\n')
FOR
PsiElement(for)('for')
PsiWhiteSpace(' ')
PsiElement(LPAR)('(')
LOOP_PARAMETER
PsiElement(IDENTIFIER)('arg')
PsiWhiteSpace(' ')
PsiElement(in)('in')
PsiWhiteSpace(' ')
LOOP_RANGE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('args')
PsiElement(RPAR)(')')
PsiWhiteSpace(' ')
BODY
BLOCK
PsiElement(LBRACE)('{')
PsiWhiteSpace('\n ')
CALL_EXPRESSION
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('println')
VALUE_ARGUMENT_LIST
PsiElement(LPAR)('(')
VALUE_ARGUMENT
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('arg')
PsiElement(RPAR)(')')
PsiWhiteSpace('\n')
PsiElement(RBRACE)('}')
@@ -0,0 +1 @@
println(1)
@@ -0,0 +1,12 @@
JetFile: SimpleScript.ktscript
SCRIPT
BLOCK
CALL_EXPRESSION
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('println')
VALUE_ARGUMENT_LIST
PsiElement(LPAR)('(')
VALUE_ARGUMENT
INTEGER_CONSTANT
PsiElement(INTEGER_LITERAL)('1')
PsiElement(RPAR)(')')
@@ -20,6 +20,7 @@ import com.intellij.openapi.application.PathManager;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.parsing.JetParser;
import java.io.File;
import java.io.FileFilter;
@@ -67,7 +68,7 @@ public abstract class JetTestCaseBuilder {
public static FilenameFilter kotlinFilter = new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".kt") || name.endsWith("jet");
return name.endsWith(".kt") || name.endsWith("jet") || name.endsWith("." + JetParser.KTSCRIPT_FILE_SUFFIX);
}
};
@@ -136,6 +136,7 @@ public class JetParsingTest extends ParsingTestCase {
suite.addTest(JetTestCaseBuilder.suiteForDirectory(prefix, "/", false, factory));
suite.addTest(JetTestCaseBuilder.suiteForDirectory(prefix, "examples", true, factory));
suite.addTest(JetTestCaseBuilder.suiteForDirectory(prefix, "greatSyntacticShift", true, factory));
suite.addTest(JetTestCaseBuilder.suiteForDirectory(prefix, "script", true, factory));
return suite;
}