parse kotlin scripts
http://confluence.jetbrains.net/display/~stepan.koltsov/REPL
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
+19
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user