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.psi.JetPsiFactory;
035 import org.jetbrains.jet.lang.resolve.BindingContext;
036 import org.jetbrains.jet.utils.fileUtils.FileUtilsPackage;
037 import org.jetbrains.js.compiler.JsSourceGenerationVisitor;
038 import org.jetbrains.js.compiler.sourcemap.SourceMap3Builder;
039 import org.jetbrains.js.compiler.sourcemap.SourceMapBuilder;
040 import org.jetbrains.k2js.analyze.AnalyzerFacadeForJS;
041 import org.jetbrains.k2js.config.Config;
042 import org.jetbrains.k2js.facade.exceptions.TranslationException;
043 import org.jetbrains.k2js.translate.general.Translation;
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 = JetPsiFactory.createFile(getProject(), "test", programText);
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 }