diff --git a/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/JetCoreEnvironment.java b/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/JetCoreEnvironment.java index da4a1d6660f..9526b62a6c1 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/JetCoreEnvironment.java +++ b/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/JetCoreEnvironment.java @@ -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()); diff --git a/compiler/frontend/src/org/jetbrains/jet/JetNodeTypes.java b/compiler/frontend/src/org/jetbrains/jet/JetNodeTypes.java index 241072f3482..37f74c04113 100644 --- a/compiler/frontend/src/org/jetbrains/jet/JetNodeTypes.java +++ b/compiler/frontend/src/org/jetbrains/jet/JetNodeTypes.java @@ -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); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParser.java b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParser.java index 2e510625c2f..3b57c77beb8 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParser.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParser.java @@ -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(); } + } 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 cb05ae1c528..7550cce26da 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParsing.java @@ -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]* */ diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFile.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFile.java index 84ccdd7d97f..c210ee0e273 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFile.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFile.java @@ -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 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 f2cf9f6b15b..247ffd70888 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetNamedFunction.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetNamedFunction.java @@ -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()); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetScript.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetScript.java new file mode 100644 index 00000000000..0c8d2045e48 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetScript.java @@ -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 accept(@NotNull JetVisitor visitor, D data) { + return visitor.visitScript(this, data); + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetVisitor.java index 15a6aae6621..a8c985c005e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetVisitor.java @@ -60,6 +60,10 @@ public class JetVisitor 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); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetVisitorVoid.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetVisitorVoid.java index 27763ebeca3..82fcfc9eb39 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetVisitorVoid.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetVisitorVoid.java @@ -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); } 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 index 0fdace281de..ec9135d1a9f 100644 --- 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 @@ -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 { 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 diff --git a/compiler/testData/psi/script/ComplexScript.ktscript b/compiler/testData/psi/script/ComplexScript.ktscript new file mode 100644 index 00000000000..2f084378c45 --- /dev/null +++ b/compiler/testData/psi/script/ComplexScript.ktscript @@ -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) +} diff --git a/compiler/testData/psi/script/ComplexScript.txt b/compiler/testData/psi/script/ComplexScript.txt new file mode 100644 index 00000000000..4c5035734f3 --- /dev/null +++ b/compiler/testData/psi/script/ComplexScript.txt @@ -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)('}') diff --git a/compiler/testData/psi/script/SimpleScript.ktscript b/compiler/testData/psi/script/SimpleScript.ktscript new file mode 100644 index 00000000000..458f620a850 --- /dev/null +++ b/compiler/testData/psi/script/SimpleScript.ktscript @@ -0,0 +1 @@ +println(1) diff --git a/compiler/testData/psi/script/SimpleScript.txt b/compiler/testData/psi/script/SimpleScript.txt new file mode 100644 index 00000000000..ede34cb06e1 --- /dev/null +++ b/compiler/testData/psi/script/SimpleScript.txt @@ -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)(')') diff --git a/compiler/tests/org/jetbrains/jet/JetTestCaseBuilder.java b/compiler/tests/org/jetbrains/jet/JetTestCaseBuilder.java index e847e4215d4..99b58176f99 100644 --- a/compiler/tests/org/jetbrains/jet/JetTestCaseBuilder.java +++ b/compiler/tests/org/jetbrains/jet/JetTestCaseBuilder.java @@ -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); } }; diff --git a/compiler/tests/org/jetbrains/jet/parsing/JetParsingTest.java b/compiler/tests/org/jetbrains/jet/parsing/JetParsingTest.java index 5a336783d91..4af45f6bb38 100644 --- a/compiler/tests/org/jetbrains/jet/parsing/JetParsingTest.java +++ b/compiler/tests/org/jetbrains/jet/parsing/JetParsingTest.java @@ -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; }