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.jet.cli.js;
018
019 import com.google.common.base.Function;
020 import com.google.common.base.Joiner;
021 import com.google.common.base.Predicates;
022 import com.google.common.collect.Iterables;
023 import com.intellij.openapi.Disposable;
024 import com.intellij.openapi.project.Project;
025 import com.intellij.openapi.util.io.FileUtil;
026 import com.intellij.openapi.vfs.VirtualFile;
027 import com.intellij.psi.PsiFile;
028 import jet.Function0;
029 import org.jetbrains.annotations.NotNull;
030 import org.jetbrains.annotations.Nullable;
031 import org.jetbrains.jet.analyzer.AnalyzeExhaust;
032 import org.jetbrains.jet.cli.common.CLICompiler;
033 import org.jetbrains.jet.cli.common.ExitCode;
034 import org.jetbrains.jet.cli.common.messages.AnalyzerWithCompilerReport;
035 import org.jetbrains.jet.cli.common.messages.CompilerMessageLocation;
036 import org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity;
037 import org.jetbrains.jet.cli.common.messages.MessageCollector;
038 import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment;
039 import org.jetbrains.jet.config.CommonConfigurationKeys;
040 import org.jetbrains.jet.config.CompilerConfiguration;
041 import org.jetbrains.jet.lang.psi.JetFile;
042 import org.jetbrains.k2js.analyze.AnalyzerFacadeForJS;
043 import org.jetbrains.k2js.config.*;
044 import org.jetbrains.k2js.facade.K2JSTranslator;
045 import org.jetbrains.k2js.facade.MainCallParameters;
046
047 import java.io.File;
048 import java.util.Arrays;
049 import java.util.List;
050
051 import static org.jetbrains.jet.cli.common.ExitCode.COMPILATION_ERROR;
052 import static org.jetbrains.jet.cli.common.ExitCode.OK;
053 import static org.jetbrains.jet.cli.common.messages.CompilerMessageLocation.NO_LOCATION;
054
055 public class K2JSCompiler extends CLICompiler<K2JSCompilerArguments> {
056
057 public static void main(String... args) {
058 doMain(new K2JSCompiler(), args);
059 }
060
061 @NotNull
062 @Override
063 protected K2JSCompilerArguments createArguments() {
064 return new K2JSCompilerArguments();
065 }
066
067
068 @NotNull
069 @Override
070 protected ExitCode doExecute(K2JSCompilerArguments arguments, MessageCollector messageCollector, Disposable rootDisposable) {
071 if (arguments.sourceFiles == null) {
072 messageCollector.report(CompilerMessageSeverity.ERROR, "Specify sources location via -sourceFiles", NO_LOCATION);
073 return ExitCode.INTERNAL_ERROR;
074 }
075
076 CompilerConfiguration configuration = new CompilerConfiguration();
077 configuration.addAll(CommonConfigurationKeys.SOURCE_ROOTS_KEY, Arrays.asList(arguments.sourceFiles));
078 JetCoreEnvironment environmentForJS = new JetCoreEnvironment(rootDisposable, configuration);
079
080 Project project = environmentForJS.getProject();
081
082 ClassPathLibrarySourcesLoader sourceLoader = new ClassPathLibrarySourcesLoader(project);
083 List<JetFile> sourceFiles = sourceLoader.findSourceFiles();
084 environmentForJS.getSourceFiles().addAll(sourceFiles);
085
086 if (arguments.isVerbose()) {
087 reportCompiledSourcesList(messageCollector, environmentForJS);
088 }
089
090 Config config = getConfig(arguments, project);
091 if (analyzeAndReportErrors(messageCollector, environmentForJS.getSourceFiles(), config)) {
092 return COMPILATION_ERROR;
093 }
094
095 String outputFile = arguments.outputFile;
096 if (outputFile == null) {
097 messageCollector.report(CompilerMessageSeverity.ERROR, "Specify output file via -output", CompilerMessageLocation.NO_LOCATION);
098 return ExitCode.INTERNAL_ERROR;
099 }
100
101 MainCallParameters mainCallParameters = arguments.createMainCallParameters();
102 return translateAndGenerateOutputFile(mainCallParameters, environmentForJS, config, outputFile);
103 }
104
105 private static void reportCompiledSourcesList(@NotNull MessageCollector messageCollector,
106 @NotNull JetCoreEnvironment environmentForJS) {
107 List<JetFile> files = environmentForJS.getSourceFiles();
108 Iterable<String> fileNames = Iterables.transform(files, new Function<JetFile, String>() {
109 @Override
110 public String apply(@Nullable JetFile file) {
111 assert file != null;
112 VirtualFile virtualFile = file.getVirtualFile();
113 if (virtualFile != null) {
114 return FileUtil.toSystemIndependentName(virtualFile.getPath());
115 }
116 return file.getName() + "(no virtual file)";
117 }
118 });
119 messageCollector.report(CompilerMessageSeverity.LOGGING, "Compiling source files: " + Joiner.on(", ").join(fileNames),
120 CompilerMessageLocation.NO_LOCATION);
121 }
122
123 @NotNull
124 private static ExitCode translateAndGenerateOutputFile(
125 @NotNull MainCallParameters mainCall,
126 @NotNull JetCoreEnvironment environmentForJS,
127 @NotNull Config config,
128 @NotNull String outputFile
129 ) {
130 try {
131 K2JSTranslator.translateWithMainCallParametersAndSaveToFile(mainCall, environmentForJS.getSourceFiles(), outputFile, config);
132 }
133 catch (Exception e) {
134 throw new RuntimeException(e);
135 }
136 return OK;
137 }
138
139 private static boolean analyzeAndReportErrors(@NotNull MessageCollector messageCollector,
140 @NotNull final List<JetFile> sources, @NotNull final Config config) {
141 AnalyzerWithCompilerReport analyzerWithCompilerReport = new AnalyzerWithCompilerReport(messageCollector);
142 analyzerWithCompilerReport.analyzeAndReport(new Function0<AnalyzeExhaust>() {
143 @Override
144 public AnalyzeExhaust invoke() {
145 return AnalyzerFacadeForJS.analyzeFiles(sources, Predicates.<PsiFile>alwaysTrue(), config);
146 }
147 }, sources);
148 return analyzerWithCompilerReport.hasErrors();
149 }
150
151 @NotNull
152 private static Config getConfig(@NotNull K2JSCompilerArguments arguments, @NotNull Project project) {
153 EcmaVersion ecmaVersion = EcmaVersion.fromString(arguments.target);
154 String moduleId = FileUtil.getNameWithoutExtension(new File(arguments.outputFile));
155 if (arguments.libraryFiles != null) {
156 return new LibrarySourcesConfig(project, moduleId, Arrays.asList(arguments.libraryFiles), ecmaVersion);
157 }
158 else {
159 // lets discover the JS library definitions on the classpath
160 return new ClassPathLibraryDefintionsConfig(project, moduleId, ecmaVersion);
161 }
162 }
163 }