From f8391619a513e6389df19e63817e629d529026fa Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Sun, 29 Jul 2012 21:32:53 +0300 Subject: [PATCH] configurable script languages --- .../cli/jvm/compiler/JetCoreEnvironment.java | 2 +- .../compiler/KotlinToJVMBytecodeCompiler.java | 8 ---- .../jetbrains/jet/lang/parsing/JetParser.java | 9 ++-- .../jet/lang/parsing/JetParserDefinition.java | 41 ++++++++++++++++- .../jet/lang/parsing/JetScriptDefinition.java | 44 +++++++++++++++++++ .../lang/resolve/AnalyzerScriptParameter.java | 4 ++ .../lang/resolve/ScriptHeaderResolver.java | 15 ++++++- .../jet/lang/resolve/TopDownAnalyzer.java | 2 - compiler/testData/codegen/script/fib.lang.kt | 8 ++++ .../org/jetbrains/jet/JetTestCaseBuilder.java | 3 +- .../jetbrains/jet/codegen/ScriptGenTest.java | 21 +++++++++ 11 files changed, 139 insertions(+), 18 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetScriptDefinition.java create mode 100644 compiler/testData/codegen/script/fib.lang.kt 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 6a704dcd0f2..6d9a3243544 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 @@ -81,7 +81,7 @@ public class JetCoreEnvironment { applicationEnvironment.registerFileType(JetFileType.INSTANCE, "kt"); applicationEnvironment.registerFileType(JetFileType.INSTANCE, "kts"); applicationEnvironment.registerFileType(JetFileType.INSTANCE, "ktm"); - applicationEnvironment.registerFileType(JetFileType.INSTANCE, JetParser.KTSCRIPT_FILE_SUFFIX); // should be renamed to kts + applicationEnvironment.registerFileType(JetFileType.INSTANCE, JetParserDefinition.KTSCRIPT_FILE_SUFFIX); // should be renamed to kts applicationEnvironment.registerFileType(JetFileType.INSTANCE, "jet"); applicationEnvironment.registerParserDefinition(new JavaParserDefinition()); applicationEnvironment.registerParserDefinition(new JetParserDefinition()); diff --git a/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java b/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java index 754a8c726b6..41ea111b055 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java +++ b/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.java @@ -30,11 +30,9 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.analyzer.AnalyzeExhaust; import org.jetbrains.jet.cli.common.CompilerPlugin; import org.jetbrains.jet.cli.common.CompilerPluginContext; -import org.jetbrains.jet.cli.common.ExitCode; import org.jetbrains.jet.cli.common.messages.*; import org.jetbrains.jet.cli.common.util.CompilerPathUtil; import org.jetbrains.jet.cli.jvm.JVMConfigurationKeys; -import org.jetbrains.jet.cli.jvm.repl.ReplFromTerminal; import org.jetbrains.jet.codegen.*; import org.jetbrains.jet.config.CommonConfigurationKeys; import org.jetbrains.jet.config.CompilerConfiguration; @@ -48,11 +46,9 @@ import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.plugin.JetMainDetector; import org.jetbrains.jet.utils.ExceptionUtils; -import org.jetbrains.jet.utils.PathUtil; import org.jetbrains.jet.utils.Progress; import java.io.*; -import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.net.URLClassLoader; import java.util.Collection; @@ -60,10 +56,6 @@ import java.util.Collections; import java.util.LinkedList; import java.util.List; -import static org.jetbrains.jet.cli.common.ExitCode.COMPILATION_ERROR; -import static org.jetbrains.jet.cli.common.ExitCode.INTERNAL_ERROR; -import static org.jetbrains.jet.cli.common.ExitCode.OK; - /** * @author yole * @author abreslav 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 3b57c77beb8..4c1c0b59827 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParser.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParser.java @@ -27,7 +27,11 @@ import com.intellij.psi.tree.IElementType; import org.jetbrains.annotations.NotNull; public class JetParser implements PsiParser { - public static final String KTSCRIPT_FILE_SUFFIX = "ktscript"; + private JetParserDefinition parserDefinition; + + public JetParser(JetParserDefinition parserDefinition) { + this.parserDefinition = parserDefinition; + } @Override @NotNull @@ -39,7 +43,7 @@ public class JetParser implements PsiParser { @NotNull public ASTNode parse(IElementType iElementType, PsiBuilder psiBuilder, PsiFile psiFile) { JetParsing jetParsing = JetParsing.createForTopLevel(new SemanticWhitespaceAwarePsiBuilderImpl(psiBuilder)); - if (psiFile.getName().endsWith("." + KTSCRIPT_FILE_SUFFIX)) { + if (parserDefinition.isScript(psiFile)) { jetParsing.parseScript(); } else { @@ -47,5 +51,4 @@ public class JetParser implements PsiParser { } return psiBuilder.getTreeBuilt(); } - } 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 7929d9e221f..0f952862faa 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParserDefinition.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetParserDefinition.java @@ -20,6 +20,7 @@ package org.jetbrains.jet.lang.parsing; import com.intellij.lang.ASTNode; +import com.intellij.lang.LanguageParserDefinitions; import com.intellij.lang.ParserDefinition; import com.intellij.lang.PsiParser; import com.intellij.lexer.Lexer; @@ -34,18 +35,39 @@ import org.jetbrains.jet.JetNodeType; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.stubs.elements.JetStubElementType; import org.jetbrains.jet.lang.psi.stubs.elements.JetStubElementTypes; +import org.jetbrains.jet.lang.resolve.AnalyzerScriptParameter; +import org.jetbrains.jet.lang.resolve.name.Name; +import org.jetbrains.jet.lang.types.ref.JetTypeName; import org.jetbrains.jet.lexer.JetLexer; import org.jetbrains.jet.lexer.JetTokens; +import org.jetbrains.jet.plugin.JetLanguage; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; public class JetParserDefinition implements ParserDefinition { + public static final String KTSCRIPT_FILE_SUFFIX = "ktscript"; + + private HashMap scripts = new HashMap(); public JetParserDefinition() { + // .ktscript will take parameters explicitly specified on compilation + JetScriptDefinition standardScript = new JetScriptDefinition(".ktscript", Collections.emptyList()); + addScriptDefinition(standardScript); + //todo: ApplicationManager.getApplication() is null during JetParsingTest setting up /*if (!ApplicationManager.getApplication().isCommandLine()) { }*/ } + @NotNull + public static JetParserDefinition getInstance() { + return (JetParserDefinition)LanguageParserDefinitions.INSTANCE.forLanguage(JetLanguage.INSTANCE); + } + @Override @NotNull public Lexer createLexer(Project project) { @@ -54,7 +76,7 @@ public class JetParserDefinition implements ParserDefinition { @Override public PsiParser createParser(Project project) { - return new JetParser(); + return new JetParser(this); } @Override @@ -99,4 +121,21 @@ public class JetParserDefinition implements ParserDefinition { public SpaceRequirements spaceExistanceTypeBetweenTokens(ASTNode astNode, ASTNode astNode1) { return SpaceRequirements.MAY; } + + public JetScriptDefinition findScriptDefinition(PsiFile psiFile) { + String name = psiFile.getName(); + for (Map.Entry e : scripts.entrySet()) { + if(name.endsWith(e.getKey())) + return e.getValue(); + } + return null; + } + + public boolean isScript(PsiFile psiFile) { + return findScriptDefinition(psiFile) != null; + } + + public void addScriptDefinition(@NotNull JetScriptDefinition scriptDefinition) { + scripts.put(scriptDefinition.getExtension(), scriptDefinition); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetScriptDefinition.java b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetScriptDefinition.java new file mode 100644 index 00000000000..05f6f7623e7 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/parsing/JetScriptDefinition.java @@ -0,0 +1,44 @@ +/* + * 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.parsing; + +import org.jetbrains.jet.lang.resolve.AnalyzerScriptParameter; + +import java.util.Arrays; +import java.util.List; + +public class JetScriptDefinition { + private final String extension; + private final List parameters; + + public JetScriptDefinition(String extension, List scriptParameters) { + this.extension = extension; + parameters = scriptParameters; + } + + public JetScriptDefinition(String extension, AnalyzerScriptParameter... scriptParameters) { + this(extension, Arrays.asList(scriptParameters)); + } + + public List getScriptParameters() { + return parameters; + } + + public String getExtension() { + return extension; + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzerScriptParameter.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzerScriptParameter.java index eb26a3a4b6b..0e08d55d12a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzerScriptParameter.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnalyzerScriptParameter.java @@ -34,6 +34,10 @@ public class AnalyzerScriptParameter { this.type = type; } + public AnalyzerScriptParameter(@NotNull String name, @NotNull String type) { + this(Name.identifier(name), JetTypeName.parse(type)); + } + @NotNull public Name getName() { return name; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ScriptHeaderResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ScriptHeaderResolver.java index 186517ddec7..01543c2ad08 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ScriptHeaderResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ScriptHeaderResolver.java @@ -18,9 +18,14 @@ package org.jetbrains.jet.lang.resolve; import com.google.common.collect.Lists; import com.intellij.openapi.util.Key; +import com.intellij.psi.util.PsiUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.jet.lang.parsing.JetParserDefinition; +import org.jetbrains.jet.lang.parsing.JetScriptDefinition; +import org.jetbrains.jet.lang.psi.JetFile; +import org.jetbrains.jet.lang.psi.JetPsiUtil; import org.jetbrains.jet.lang.psi.JetScript; import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; import org.jetbrains.jet.lang.resolve.name.FqName; @@ -148,8 +153,15 @@ public class ScriptHeaderResolver { scope.setImplicitReceiver(descriptor.getImplicitReceiver()); + JetFile file = (JetFile) declaration.getContainingFile(); + JetScriptDefinition scriptDefinition = JetParserDefinition.getInstance().findScriptDefinition(file); + int index = 0; - for (AnalyzerScriptParameter scriptParameter : topDownAnalysisParameters.getScriptParameters()) { + List scriptParameters = !scriptDefinition.getScriptParameters().isEmpty() + ? scriptDefinition.getScriptParameters() + : topDownAnalysisParameters.getScriptParameters(); + + for (AnalyzerScriptParameter scriptParameter : scriptParameters) { ValueParameterDescriptor parameter = resolveScriptParameter(scriptParameter, index, descriptor); valueParameters.add(parameter); scope.addVariableDescriptor(parameter); @@ -159,5 +171,4 @@ public class ScriptHeaderResolver { descriptor.setValueParameters(valueParameters); } } - } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index d2be06c6289..06ea8ed9af9 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -27,13 +27,11 @@ import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.JetClassOrObject; import org.jetbrains.jet.lang.psi.JetDeclaration; import org.jetbrains.jet.lang.psi.JetFile; -import org.jetbrains.jet.lang.psi.JetObjectDeclaration; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.WritableScope; import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl; -import org.jetbrains.jet.lang.types.DependencyClassByQualifiedNameResolver; import org.jetbrains.jet.lang.types.lang.JetStandardClasses; import javax.inject.Inject; diff --git a/compiler/testData/codegen/script/fib.lang.kt b/compiler/testData/codegen/script/fib.lang.kt new file mode 100644 index 00000000000..87b9ac5c54a --- /dev/null +++ b/compiler/testData/codegen/script/fib.lang.kt @@ -0,0 +1,8 @@ +// this script expected parameter num : Int + +fun fib(n: Int): Int { + val v = if(n < 2) 1 else fib(n-1) + fib(n-2) + return v +} + +val result = fib(num) diff --git a/compiler/tests/org/jetbrains/jet/JetTestCaseBuilder.java b/compiler/tests/org/jetbrains/jet/JetTestCaseBuilder.java index 99b58176f99..8d10e9b454e 100644 --- a/compiler/tests/org/jetbrains/jet/JetTestCaseBuilder.java +++ b/compiler/tests/org/jetbrains/jet/JetTestCaseBuilder.java @@ -21,6 +21,7 @@ import junit.framework.Test; import junit.framework.TestSuite; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.parsing.JetParser; +import org.jetbrains.jet.lang.parsing.JetParserDefinition; import java.io.File; import java.io.FileFilter; @@ -68,7 +69,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") || name.endsWith("." + JetParser.KTSCRIPT_FILE_SUFFIX); + return name.endsWith(".kt") || name.endsWith(".jet") || name.endsWith("." + JetParserDefinition.KTSCRIPT_FILE_SUFFIX); } }; diff --git a/compiler/tests/org/jetbrains/jet/codegen/ScriptGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/ScriptGenTest.java index da53ec6f959..98c63b649b3 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/ScriptGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/ScriptGenTest.java @@ -17,8 +17,15 @@ package org.jetbrains.jet.codegen; import org.jetbrains.jet.ConfigurationKind; +import org.jetbrains.jet.lang.parsing.JetParserDefinition; +import org.jetbrains.jet.lang.parsing.JetScriptDefinition; +import org.jetbrains.jet.lang.resolve.AnalyzerScriptParameter; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.List; /** * @author Stepan Koltsov @@ -86,4 +93,18 @@ public class ScriptGenTest extends CodegenTestCase { blackBoxFile("script/empty.ktscript"); } + public void testLanguage() { + JetParserDefinition.getInstance().addScriptDefinition(new JetScriptDefinition(".lang.kt", new AnalyzerScriptParameter("num","jet.Int"))); + loadFile("script/fib.lang.kt"); + final Class aClass = loadClass("Script", generateClassesInFile()); + try { + Constructor constructor = aClass.getConstructor(int.class); + Field result = aClass.getField("result"); + Object script = constructor.newInstance(5); + assertEquals(8,result.get(script)); + } + catch (Exception e) { + throw new RuntimeException(e); + } + } }