diff --git a/js/js.tests/test/org/jetbrains/k2js/test/BasicTest.java b/js/js.tests/test/org/jetbrains/k2js/test/BasicTest.java index bdfba923061..3adf4798ba5 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/BasicTest.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/BasicTest.java @@ -42,9 +42,6 @@ public abstract class BasicTest extends TestWithEnvironment { private static final String TEST_FILES = "js/js.translator/testFiles/"; private static final String CASES = "cases/"; private static final String OUT = "out/"; - private static final String KOTLIN_JS_LIB = pathToTestFilesRoot() + "kotlin_lib.js"; - private static final String KOTLIN_JS_LIB_ECMA_3 = pathToTestFilesRoot() + "kotlin_lib_ecma3.js"; - private static final String KOTLIN_JS_LIB_ECMA_5 = pathToTestFilesRoot() + "kotlin_lib_ecma5.js"; private static final String EXPECTED = "expected/"; @NotNull @@ -90,10 +87,7 @@ public abstract class BasicTest extends TestWithEnvironment { @NotNull protected List additionalJSFiles(@NotNull EcmaVersion ecmaVersion) { - List list = Lists.newArrayList(); - list.add(ecmaVersion == EcmaVersion.v5 ? KOTLIN_JS_LIB_ECMA_5 : KOTLIN_JS_LIB_ECMA_3); - list.add(KOTLIN_JS_LIB); - return list; + return Lists.newArrayList(); } protected void generateJavaScriptFiles(@NotNull String kotlinFilename, @@ -141,7 +135,7 @@ public abstract class BasicTest extends TestWithEnvironment { } @NotNull - protected static String pathToTestFilesRoot() { + public static String pathToTestFilesRoot() { return TEST_FILES; } diff --git a/js/js.tests/test/org/jetbrains/k2js/test/rhino/RhinoFunctionResultChecker.java b/js/js.tests/test/org/jetbrains/k2js/test/rhino/RhinoFunctionResultChecker.java index 396ff1dba12..55d4f847bf7 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/rhino/RhinoFunctionResultChecker.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/rhino/RhinoFunctionResultChecker.java @@ -20,6 +20,7 @@ import org.jetbrains.annotations.Nullable; import org.mozilla.javascript.Context; import org.mozilla.javascript.Scriptable; +import static org.jetbrains.k2js.test.rhino.RhinoUtils.flushSystemOut; import static org.junit.Assert.assertEquals; /** @@ -44,6 +45,7 @@ public class RhinoFunctionResultChecker implements RhinoResultChecker { @Override public void runChecks(Context context, Scriptable scope) throws Exception { Object result = evaluateFunction(context, scope); + flushSystemOut(context, scope); assertResultValid(result); } diff --git a/js/js.tests/test/org/jetbrains/k2js/test/rhino/RhinoSystemOutputChecker.java b/js/js.tests/test/org/jetbrains/k2js/test/rhino/RhinoSystemOutputChecker.java index 84352c065d9..38a4d549b98 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/rhino/RhinoSystemOutputChecker.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/rhino/RhinoSystemOutputChecker.java @@ -17,6 +17,7 @@ package org.jetbrains.k2js.test.rhino; import org.jetbrains.annotations.NotNull; +import org.jetbrains.k2js.facade.K2JSTranslator; import org.mozilla.javascript.Context; import org.mozilla.javascript.Scriptable; @@ -44,12 +45,15 @@ public final class RhinoSystemOutputChecker implements RhinoResultChecker { + "END_OF_EXPECTED\n", trimmedExpected.equals(trimmedActual)); } + @NotNull private static String getSystemOutput(@NotNull Context context, @NotNull Scriptable scope) { - Object output = context.evaluateString(scope, "Kotlin.System.output()", "test", 0, null); + Object output = context.evaluateString(scope, K2JSTranslator.GET_SYSTEM_OUT, "test", 0, null); + RhinoUtils.flushSystemOut(context, scope); assertTrue("Output should be a string.", output instanceof String); return (String) output; } + @NotNull public static String trimSpace(@NotNull String s) { String[] choppedUpString = s.trim().split("\\s"); StringBuilder sb = new StringBuilder(); diff --git a/js/js.tests/test/org/jetbrains/k2js/test/rhino/RhinoUtils.java b/js/js.tests/test/org/jetbrains/k2js/test/rhino/RhinoUtils.java index 1d8d2ff982b..bb2dc39d996 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/rhino/RhinoUtils.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/rhino/RhinoUtils.java @@ -16,66 +16,135 @@ package org.jetbrains.k2js.test.rhino; +import closurecompiler.internal.com.google.common.collect.Maps; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.k2js.config.EcmaVersion; +import org.jetbrains.k2js.facade.K2JSTranslator; import org.mozilla.javascript.Context; import org.mozilla.javascript.Scriptable; +import org.mozilla.javascript.ScriptableObject; import java.io.FileReader; import java.util.List; import java.util.Map; import java.util.Set; +import static org.jetbrains.jet.utils.ExceptionUtils.rethrow; +import static org.jetbrains.k2js.test.BasicTest.pathToTestFilesRoot; + /** * @author Pavel Talanov */ public final class RhinoUtils { + public static final String KOTLIN_JS_LIB_COMMON = pathToTestFilesRoot() + "kotlin_lib.js"; + private static final String KOTLIN_JS_LIB_ECMA_3 = pathToTestFilesRoot() + "kotlin_lib_ecma3.js"; + private static final String KOTLIN_JS_LIB_ECMA_5 = pathToTestFilesRoot() + "kotlin_lib_ecma5.js"; + private RhinoUtils() { } private static void runFileWithRhino(@NotNull String inputFile, - @NotNull Context context, - @NotNull Scriptable scope) throws Exception { + @NotNull Context context, + @NotNull Scriptable scope) throws Exception { FileReader reader = new FileReader(inputFile); try { context.evaluateReader(scope, reader, inputFile, 1, null); - } finally { + } + finally { reader.close(); } } public static void runRhinoTest(@NotNull List fileNames, - @NotNull RhinoResultChecker checker) throws Exception { - + @NotNull RhinoResultChecker checker) throws Exception { runRhinoTest(fileNames, checker, null, EcmaVersion.defaultVersion()); } public static void runRhinoTest(@NotNull List fileNames, - @NotNull RhinoResultChecker checker, - @Nullable Map variables, - @NotNull EcmaVersion ecmaVersion) throws Exception { + @NotNull RhinoResultChecker checker, + @Nullable Map variables, + @NotNull EcmaVersion ecmaVersion) throws Exception { + Context context = createContext(ecmaVersion); + try { + Scriptable scope = getScope(ecmaVersion, context); + putGlobalVariablesIntoScope(scope, variables); + for (String filename : fileNames) { + runFileWithRhino(filename, context, scope); + } + checker.runChecks(context, scope); + } + finally { + Context.exit(); + } + } + + @NotNull + private static Scriptable getScope(@NotNull EcmaVersion version, @NotNull Context context) { + ScriptableObject scope = context.initStandardObjects(null, false); + scope.setParentScope(getParentScope(version, context)); + return scope; + } + + @NotNull + private static Scriptable getParentScope(@NotNull EcmaVersion version, @NotNull Context context) { + Scriptable parentScope = versionToScope.get(version); + if (parentScope == null) { + parentScope = initScope(version, context); + versionToScope.put(version, parentScope); + } + return parentScope; + } + + @NotNull + private static Scriptable initScope(@NotNull EcmaVersion version, @NotNull Context context) { + ScriptableObject scope = context.initStandardObjects(); + try { + runFileWithRhino(getKotlinLibFile(version), context, scope); + runFileWithRhino(KOTLIN_JS_LIB_COMMON, context, scope); + } + catch (Exception e) { + throw rethrow(e); + } + scope.sealObject(); + return scope; + } + + + //TODO: + @NotNull + private static Context createContext(@NotNull EcmaVersion ecmaVersion) { Context context = Context.enter(); if (ecmaVersion == EcmaVersion.v5) { // actually, currently, doesn't matter because dart doesn't produce js 1.8 code (expression closures) context.setLanguageVersion(Context.VERSION_1_8); } + return context; + } - Scriptable scope = context.initStandardObjects(); - if (variables != null) { - Set> entries = variables.entrySet(); - for (Map.Entry entry : entries) { - String name = entry.getKey(); - Object value = entry.getValue(); - scope.put(name, scope, value); - } + private static void putGlobalVariablesIntoScope(@NotNull Scriptable scope, @Nullable Map variables) { + if (variables == null) { + return; } - for (String filename : fileNames) { - runFileWithRhino(filename, context, scope); + Set> entries = variables.entrySet(); + for (Map.Entry entry : entries) { + String name = entry.getKey(); + Object value = entry.getValue(); + scope.put(name, scope, value); } - checker.runChecks(context, scope); - Context.exit(); + } + + @NotNull + private static final Map versionToScope = Maps.newHashMap(); + + @NotNull + public static String getKotlinLibFile(@NotNull EcmaVersion ecmaVersion) { + return ecmaVersion == EcmaVersion.v5 ? KOTLIN_JS_LIB_ECMA_5 : KOTLIN_JS_LIB_ECMA_3; + } + + static void flushSystemOut(@NotNull Context context, @NotNull Scriptable scope) { + context.evaluateString(scope, K2JSTranslator.FLUSH_SYSTEM_OUT, "test", 0, null); } } diff --git a/js/js.tests/test/org/jetbrains/k2js/test/utils/TranslationUtils.java b/js/js.tests/test/org/jetbrains/k2js/test/utils/TranslationUtils.java index 80c27753f95..0fb0a33aa0c 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/utils/TranslationUtils.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/utils/TranslationUtils.java @@ -20,6 +20,7 @@ import closurecompiler.internal.com.google.common.collect.Maps; import com.google.dart.compiler.backend.js.ast.JsProgram; import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.k2js.config.EcmaVersion; import org.jetbrains.k2js.facade.K2JSTranslator; @@ -29,7 +30,6 @@ import org.jetbrains.k2js.test.config.TestConfig; import java.io.File; import java.io.FileWriter; -import java.util.Collections; import java.util.List; import java.util.Map; @@ -46,21 +46,16 @@ public final class TranslationUtils { @NotNull private static final Map translators = Maps.newHashMap(); - public static void translateFile(@NotNull Project project, @NotNull String inputFile, - @NotNull String outputFile, @NotNull MainCallParameters mainCallParameters, @NotNull EcmaVersion version) throws Exception { - translateFiles(project, Collections.singletonList(inputFile), outputFile, mainCallParameters, version, null); - } - public static void translateFiles(@NotNull Project project, @NotNull List inputFiles, @NotNull String outputFile, @NotNull MainCallParameters mainCallParameters, @NotNull EcmaVersion version, - List rawStatements) throws Exception { + @Nullable List rawStatements) throws Exception { List psiFiles = createPsiFileList(inputFiles, project); JsProgram program = getTranslator(project, version).generateProgram(psiFiles, mainCallParameters, rawStatements); FileWriter writer = new FileWriter(new File(outputFile)); try { - writer.write(CodeGenerator.toString(program, null)); + writer.write(CodeGenerator.generateProgramToString(program, null)); } finally { writer.close(); diff --git a/js/js.translator/src/org/jetbrains/k2js/facade/K2JSTranslator.java b/js/js.translator/src/org/jetbrains/k2js/facade/K2JSTranslator.java index ddd6dc3a352..eac933e6357 100644 --- a/js/js.translator/src/org/jetbrains/k2js/facade/K2JSTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/facade/K2JSTranslator.java @@ -20,13 +20,13 @@ import com.google.common.collect.Lists; import com.google.dart.compiler.backend.js.ast.JsProgram; import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.types.lang.JetStandardLibrary; import org.jetbrains.k2js.analyze.AnalyzerFacadeForJS; import org.jetbrains.k2js.config.Config; import org.jetbrains.k2js.facade.exceptions.TranslationException; -import org.jetbrains.k2js.generate.CodeGenerator; import org.jetbrains.k2js.translate.general.Translation; import org.jetbrains.k2js.utils.JetFileUtils; @@ -37,6 +37,7 @@ import java.util.List; import static org.jetbrains.k2js.facade.FacadeUtils.parseString; import static org.jetbrains.k2js.facade.FacadeUtils.writeCodeToFile; +import static org.jetbrains.k2js.generate.CodeGenerator.generateProgramToString; /** * @author Pavel Talanov @@ -45,6 +46,9 @@ import static org.jetbrains.k2js.facade.FacadeUtils.writeCodeToFile; */ public final class K2JSTranslator { + public static final String FLUSH_SYSTEM_OUT = "Kotlin.System.flush();\n"; + public static final String GET_SYSTEM_OUT = "Kotlin.System.output();\n"; + public static void translateWithMainCallParametersAndSaveToFile(@NotNull MainCallParameters mainCall, @NotNull List files, @NotNull String outputPath, @@ -62,22 +66,20 @@ public final class K2JSTranslator { this.config = config; } - //TODO: web demo related method + //NOTE: web demo related method @SuppressWarnings("UnusedDeclaration") @NotNull public String translateStringWithCallToMain(@NotNull String programText, @NotNull String argumentsString) throws TranslationException { JetFile file = JetFileUtils.createPsiFile("test", programText, getProject()); String programCode = generateProgramCode(file, MainCallParameters.mainWithArguments(parseString(argumentsString)), null) + "\n"; - String flushOutput = "Kotlin.System.flush();\n"; - String programOutput = "Kotlin.System.output();\n"; - return flushOutput + programCode + programOutput; + return FLUSH_SYSTEM_OUT + programCode + GET_SYSTEM_OUT; } @NotNull - public String generateProgramCode(@NotNull JetFile file, @NotNull MainCallParameters mainCallParameters, List rawStatements) throws TranslationException { + public String generateProgramCode(@NotNull JetFile file, @NotNull MainCallParameters mainCallParameters, + @Nullable List rawStatements) throws TranslationException { JsProgram program = generateProgram(Arrays.asList(file), mainCallParameters, rawStatements); - CodeGenerator generator = new CodeGenerator(); - return generator.generateToString(program, rawStatements); + return generateProgramToString(program, rawStatements); } @NotNull @@ -85,14 +87,13 @@ public final class K2JSTranslator { throws TranslationException { List rawStatements = Lists.newArrayList(); JsProgram program = generateProgram(files, mainCallParameters, rawStatements); - CodeGenerator generator = new CodeGenerator(); - return generator.generateToString(program, rawStatements); + return generateProgramToString(program, rawStatements); } @NotNull public JsProgram generateProgram(@NotNull List filesToTranslate, @NotNull MainCallParameters mainCallParameters, - List rawStatements) + @Nullable List rawStatements) throws TranslationException { JetStandardLibrary.initialize(config.getProject()); BindingContext bindingContext = AnalyzerFacadeForJS.analyzeFilesAndCheckErrors(filesToTranslate, config); diff --git a/js/js.translator/src/org/jetbrains/k2js/generate/CodeGenerator.java b/js/js.translator/src/org/jetbrains/k2js/generate/CodeGenerator.java index 47beda0d5d4..89e100bf81a 100644 --- a/js/js.translator/src/org/jetbrains/k2js/generate/CodeGenerator.java +++ b/js/js.translator/src/org/jetbrains/k2js/generate/CodeGenerator.java @@ -21,10 +21,8 @@ import com.google.dart.compiler.backend.js.ast.JsProgram; import com.google.dart.compiler.util.DefaultTextOutput; import com.google.dart.compiler.util.TextOutput; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; import java.util.List; /** @@ -35,31 +33,16 @@ public final class CodeGenerator { @NotNull private final TextOutput output = new DefaultTextOutput(false); - public CodeGenerator() { - } - - public static void toFile(@NotNull String outputFile, @NotNull JsProgram program) throws IOException { - CodeGenerator generator = new CodeGenerator(); - generator.generateToFile(program, new File(outputFile)); + private CodeGenerator() { } @NotNull - public static String toString(@NotNull JsProgram program, List rawStatements) { + public static String generateProgramToString(@NotNull JsProgram program, @Nullable List rawStatements) { return (new CodeGenerator()).generateToString(program, rawStatements); } - public void generateToFile(@NotNull JsProgram program, @NotNull File file) throws IOException { - generateCode(program); - FileWriter writer = new FileWriter(file); - try { - writer.write(output.toString()); - } finally { - writer.close(); - } - } - @NotNull - public String generateToString(@NotNull JsProgram program, List rawStatements) { + private String generateToString(@NotNull JsProgram program, List rawStatements) { generateCode(program); if (rawStatements != null) { for (String statement : rawStatements) {