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.jvm;
018    
019    import com.google.common.base.Splitter;
020    import com.google.common.collect.Lists;
021    import com.intellij.openapi.Disposable;
022    import com.intellij.openapi.util.text.StringUtil;
023    import kotlin.modules.Module;
024    import org.jetbrains.annotations.NotNull;
025    import org.jetbrains.jet.cli.common.CLICompiler;
026    import org.jetbrains.jet.cli.common.CLIConfigurationKeys;
027    import org.jetbrains.jet.cli.common.ExitCode;
028    import org.jetbrains.jet.cli.common.arguments.CompilerArgumentsUtil;
029    import org.jetbrains.jet.cli.common.arguments.K2JVMCompilerArguments;
030    import org.jetbrains.jet.cli.common.messages.*;
031    import org.jetbrains.jet.cli.jvm.compiler.*;
032    import org.jetbrains.jet.cli.jvm.repl.ReplFromTerminal;
033    import org.jetbrains.jet.codegen.CompilationException;
034    import org.jetbrains.jet.codegen.inline.InlineCodegenUtil;
035    import org.jetbrains.jet.config.CommonConfigurationKeys;
036    import org.jetbrains.jet.config.CompilerConfiguration;
037    import org.jetbrains.jet.lang.resolve.AnalyzerScriptParameter;
038    import org.jetbrains.jet.utils.KotlinPaths;
039    import org.jetbrains.jet.utils.KotlinPathsFromHomeDir;
040    import org.jetbrains.jet.utils.PathUtil;
041    
042    import java.io.File;
043    import java.util.Arrays;
044    import java.util.Collections;
045    import java.util.List;
046    
047    import static com.google.common.base.Predicates.in;
048    import static org.jetbrains.jet.cli.common.ExitCode.INTERNAL_ERROR;
049    import static org.jetbrains.jet.cli.common.ExitCode.OK;
050    
051    @SuppressWarnings("UseOfSystemOutOrSystemErr")
052    public class K2JVMCompiler extends CLICompiler<K2JVMCompilerArguments> {
053    
054        public static void main(String... args) {
055            doMain(new K2JVMCompiler(), args);
056        }
057    
058        @Override
059        @NotNull
060        protected ExitCode doExecute(
061                @NotNull K2JVMCompilerArguments arguments,
062                @NotNull MessageCollector messageCollector,
063                @NotNull Disposable rootDisposable
064        ) {
065            KotlinPaths paths = arguments.kotlinHome != null
066                                    ? new KotlinPathsFromHomeDir(new File(arguments.kotlinHome))
067                                    : PathUtil.getKotlinPathsForCompiler();
068    
069            messageCollector.report(CompilerMessageSeverity.LOGGING,
070                                    "Using Kotlin home directory " + paths.getHomePath(), CompilerMessageLocation.NO_LOCATION);
071    
072            CompilerConfiguration configuration = new CompilerConfiguration();
073    
074            try {
075                configuration.addAll(JVMConfigurationKeys.CLASSPATH_KEY, getClasspath(paths, arguments));
076                configuration.addAll(JVMConfigurationKeys.ANNOTATIONS_PATH_KEY, getAnnotationsPath(paths, arguments));
077            }
078            catch (Throwable t) {
079                MessageCollectorUtil.reportException(messageCollector, t);
080                return INTERNAL_ERROR;
081            }
082    
083            if (!arguments.script &&
084                arguments.module == null &&
085                arguments.src == null &&
086                arguments.freeArgs.isEmpty()
087            ) {
088                ReplFromTerminal.run(rootDisposable, configuration);
089                return ExitCode.OK;
090            }
091            else if (arguments.module != null) {
092            }
093            else if (arguments.script) {
094                configuration.add(CommonConfigurationKeys.SOURCE_ROOTS_KEY, arguments.freeArgs.get(0));
095            }
096            else {
097                if (arguments.src != null) {
098                    List<String> sourcePathsSplitByPathSeparator
099                            = Arrays.asList(arguments.src.split(StringUtil.escapeToRegexp(File.pathSeparator)));
100                    configuration.addAll(CommonConfigurationKeys.SOURCE_ROOTS_KEY, sourcePathsSplitByPathSeparator);
101                }
102                for (String freeArg : arguments.freeArgs) {
103                    configuration.add(CommonConfigurationKeys.SOURCE_ROOTS_KEY, freeArg);
104                }
105            }
106    
107            configuration.put(JVMConfigurationKeys.SCRIPT_PARAMETERS, arguments.script
108                                                                              ? CommandLineScriptUtils.scriptParameters()
109                                                                              : Collections.<AnalyzerScriptParameter>emptyList());
110    
111            configuration.put(JVMConfigurationKeys.GENERATE_NOT_NULL_ASSERTIONS, arguments.notNullAssertions);
112            configuration.put(JVMConfigurationKeys.GENERATE_NOT_NULL_PARAMETER_ASSERTIONS, arguments.notNullParamAssertions);
113            configuration.put(JVMConfigurationKeys.ENABLE_INLINE,
114                              CompilerArgumentsUtil.optionToBooleanFlag(arguments.inline, InlineCodegenUtil.DEFAULT_INLINE_FLAG));
115    
116            configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector);
117    
118            messageCollector.report(CompilerMessageSeverity.LOGGING, "Configuring the compilation environment",
119                                    CompilerMessageLocation.NO_LOCATION);
120            try {
121                configureEnvironment(configuration, arguments);
122    
123                File jar = arguments.jar != null ? new File(arguments.jar) : null;
124                File outputDir = arguments.outputDir != null ? new File(arguments.outputDir) : null;
125    
126                if (arguments.module != null) {
127                    MessageCollector sanitizedCollector = new FilteringMessageCollector(messageCollector, in(CompilerMessageSeverity.VERBOSE));
128                    List<Module> modules = CompileEnvironmentUtil.loadModuleDescriptions(paths, arguments.module, sanitizedCollector);
129    
130                    if (outputDir != null) {
131                        messageCollector.report(CompilerMessageSeverity.WARNING, "The '-output' option is ignored because '-module' is specified",
132                                                CompilerMessageLocation.NO_LOCATION);
133                    }
134    
135                    File directory = new File(arguments.module).getAbsoluteFile().getParentFile();
136                    KotlinToJVMBytecodeCompiler.compileModules(configuration, modules,
137                                                                          directory, jar,
138                                                                          arguments.includeRuntime);
139                }
140                else if (arguments.script) {
141                    List<String> scriptArgs = arguments.freeArgs.subList(1, arguments.freeArgs.size());
142                    JetCoreEnvironment environment = JetCoreEnvironment.createForProduction(rootDisposable, configuration);
143                    KotlinToJVMBytecodeCompiler.compileAndExecuteScript(paths, environment, scriptArgs);
144                }
145                else {
146                    JetCoreEnvironment environment = JetCoreEnvironment.createForProduction(rootDisposable, configuration);
147                    KotlinToJVMBytecodeCompiler.compileBunchOfSources(environment, jar, outputDir, arguments.includeRuntime);
148                }
149                return OK;
150            }
151            catch (CompilationException e) {
152                messageCollector.report(CompilerMessageSeverity.EXCEPTION, MessageRenderer.PLAIN.renderException(e),
153                                        MessageUtil.psiElementToMessageLocation(e.getElement()));
154                return INTERNAL_ERROR;
155            }
156        }
157    
158    
159        /**
160         * Allow derived classes to add additional command line arguments
161         */
162        @NotNull
163        @Override
164        protected K2JVMCompilerArguments createArguments() {
165            return new K2JVMCompilerArguments();
166        }
167    
168        @NotNull
169        private static List<File> getClasspath(@NotNull KotlinPaths paths, @NotNull K2JVMCompilerArguments arguments) {
170            List<File> classpath = Lists.newArrayList();
171            if (!arguments.noJdk) {
172                classpath.addAll(PathUtil.getJdkClassesRoots());
173            }
174            if (!arguments.noStdlib) {
175                classpath.add(paths.getRuntimePath());
176            }
177            if (arguments.classpath != null) {
178                for (String element : Splitter.on(File.pathSeparatorChar).split(arguments.classpath)) {
179                    classpath.add(new File(element));
180                }
181            }
182            return classpath;
183        }
184    
185        @NotNull
186        private static List<File> getAnnotationsPath(@NotNull KotlinPaths paths, @NotNull K2JVMCompilerArguments arguments) {
187            List<File> annotationsPath = Lists.newArrayList();
188            if (!arguments.noJdkAnnotations) {
189                annotationsPath.add(paths.getJdkAnnotationsPath());
190            }
191            if (arguments.annotations != null) {
192                for (String element : Splitter.on(File.pathSeparatorChar).split(arguments.annotations)) {
193                    annotationsPath.add(new File(element));
194                }
195            }
196            return annotationsPath;
197        }
198    
199        @Override
200        protected void checkArguments(@NotNull K2JVMCompilerArguments argument) {
201            super.checkArguments(argument);
202    
203            if (!CompilerArgumentsUtil.checkOption(argument.inline)) {
204                throw new IllegalArgumentException(CompilerArgumentsUtil.getWrongInlineOptionErrorMessage(argument.inline));
205            }
206        }
207    
208    }