001 /* 002 * Copyright 2010-2013 JetBrains s.r.o. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package org.jetbrains.k2js.facade; 018 019 import com.google.dart.compiler.backend.js.ast.JsProgram; 020 import com.google.dart.compiler.util.TextOutputImpl; 021 import com.intellij.openapi.project.Project; 022 import com.intellij.openapi.util.text.StringUtil; 023 import com.intellij.openapi.vfs.VfsUtilCore; 024 import com.intellij.openapi.vfs.VirtualFile; 025 import com.intellij.util.Function; 026 import com.intellij.util.SmartList; 027 import com.intellij.util.containers.ContainerUtil; 028 import org.jetbrains.annotations.NotNull; 029 import org.jetbrains.annotations.Nullable; 030 import org.jetbrains.jet.OutputFileCollection; 031 import org.jetbrains.jet.SimpleOutputFile; 032 import org.jetbrains.jet.SimpleOutputFileCollection; 033 import org.jetbrains.jet.lang.psi.JetFile; 034 import org.jetbrains.jet.lang.resolve.BindingContext; 035 import org.jetbrains.jet.utils.fileUtils.FileUtilsPackage; 036 import org.jetbrains.js.compiler.JsSourceGenerationVisitor; 037 import org.jetbrains.js.compiler.sourcemap.SourceMap3Builder; 038 import org.jetbrains.js.compiler.sourcemap.SourceMapBuilder; 039 import org.jetbrains.k2js.analyze.AnalyzerFacadeForJS; 040 import org.jetbrains.k2js.config.Config; 041 import org.jetbrains.k2js.facade.exceptions.TranslationException; 042 import org.jetbrains.k2js.translate.general.Translation; 043 import org.jetbrains.k2js.utils.JetFileUtils; 044 045 import java.io.File; 046 import java.io.IOException; 047 import java.util.Collections; 048 import java.util.List; 049 050 import static org.jetbrains.k2js.facade.FacadeUtils.parseString; 051 052 /** 053 * An entry point of translator. 054 */ 055 public final class K2JSTranslator { 056 057 public static final String FLUSH_SYSTEM_OUT = "Kotlin.System.flush();\n"; 058 public static final String GET_SYSTEM_OUT = "Kotlin.System.output();\n"; 059 060 public static OutputFileCollection translateWithMainCallParameters( 061 @NotNull MainCallParameters mainCall, 062 @NotNull List<JetFile> files, 063 @NotNull File outputFile, 064 @Nullable File outputPrefixFile, 065 @Nullable File outputPostfixFile, 066 @NotNull Config config 067 ) throws TranslationException, IOException { 068 K2JSTranslator translator = new K2JSTranslator(config); 069 TextOutputImpl output = new TextOutputImpl(); 070 SourceMapBuilder sourceMapBuilder = config.isSourcemap() ? new SourceMap3Builder(outputFile, output, new SourceMapBuilderConsumer()) : null; 071 String programCode = translator.generateProgramCode(files, mainCall, output, sourceMapBuilder); 072 073 String prefix = FileUtilsPackage.readTextOrEmpty(outputPrefixFile); 074 String postfix = FileUtilsPackage.readTextOrEmpty(outputPostfixFile); 075 076 StringBuilder outBuilder = new StringBuilder(programCode.length() + prefix.length() + postfix.length()); 077 outBuilder.append(prefix).append(programCode).append(postfix); 078 079 List<File> sourceFiles = ContainerUtil.map(files, new Function<JetFile, File>() { 080 @Override 081 public File fun(JetFile file) { 082 VirtualFile virtualFile = file.getOriginalFile().getVirtualFile(); 083 if (virtualFile == null) return new File(file.getName()); 084 return VfsUtilCore.virtualToIoFile(virtualFile); 085 } 086 }); 087 088 SimpleOutputFile jsFile = new SimpleOutputFile(sourceFiles, outputFile.getName(), outBuilder.toString()); 089 List<SimpleOutputFile> outputFiles = new SmartList<SimpleOutputFile>(jsFile); 090 091 if (sourceMapBuilder != null) { 092 sourceMapBuilder.skipLinesAtBeginning(StringUtil.getLineBreakCount(prefix)); 093 SimpleOutputFile sourcemapFile = new SimpleOutputFile(sourceFiles, sourceMapBuilder.getOutFile().getName(), sourceMapBuilder.build()); 094 outputFiles.add(sourcemapFile); 095 } 096 097 return new SimpleOutputFileCollection(outputFiles); 098 } 099 100 @NotNull 101 private final Config config; 102 103 public K2JSTranslator(@NotNull Config config) { 104 this.config = config; 105 } 106 107 //NOTE: web demo related method 108 @SuppressWarnings("UnusedDeclaration") 109 @NotNull 110 public String translateStringWithCallToMain(@NotNull String programText, @NotNull String argumentsString) throws TranslationException { 111 JetFile file = JetFileUtils.createJetFile("test", programText, getProject()); 112 String programCode = generateProgramCode(file, MainCallParameters.mainWithArguments(parseString(argumentsString))) + "\n"; 113 return FLUSH_SYSTEM_OUT + programCode + GET_SYSTEM_OUT; 114 } 115 116 @NotNull 117 public String generateProgramCode(@NotNull JetFile file, @NotNull MainCallParameters mainCallParameters) throws TranslationException { 118 return generateProgramCode(Collections.singletonList(file), mainCallParameters); 119 } 120 121 @NotNull 122 public String generateProgramCode(@NotNull List<JetFile> files, @NotNull MainCallParameters mainCallParameters) 123 throws TranslationException { 124 return generateProgramCode(files, mainCallParameters, new TextOutputImpl(), null); 125 } 126 127 @NotNull 128 public String generateProgramCode( 129 @NotNull List<JetFile> files, 130 @NotNull MainCallParameters mainCallParameters, 131 @NotNull TextOutputImpl output, 132 @Nullable SourceMapBuilder sourceMapBuilder 133 ) throws TranslationException { 134 JsProgram program = generateProgram(files, mainCallParameters); 135 JsSourceGenerationVisitor sourceGenerator = new JsSourceGenerationVisitor(output, sourceMapBuilder); 136 program.accept(sourceGenerator); 137 return output.toString(); 138 } 139 140 @NotNull 141 public JsProgram generateProgram(@NotNull List<JetFile> filesToTranslate, 142 @NotNull MainCallParameters mainCallParameters) 143 throws TranslationException { 144 BindingContext bindingContext = AnalyzerFacadeForJS.analyzeFilesAndCheckErrors(filesToTranslate, config); 145 return Translation.generateAst(bindingContext, filesToTranslate, mainCallParameters, config); 146 } 147 148 @NotNull 149 private Project getProject() { 150 return config.getProject(); 151 } 152 }