JS backend: started to implement source maps

#KT-927 in progress

(cherry picked from commits 5543cda, 6ed296b, 11186f9, 5b84d0b)
This commit is contained in:
develar
2013-08-23 22:12:37 +04:00
committed by Zalim Bashorov
parent e39943f9bd
commit 3ab095a4f5
18 changed files with 112 additions and 173 deletions
@@ -153,11 +153,11 @@ public class K2JSCompiler extends CLICompiler<K2JSCompilerArguments> {
EcmaVersion ecmaVersion = EcmaVersion.fromString(arguments.target);
String moduleId = FileUtil.getNameWithoutExtension(new File(arguments.outputFile));
if (arguments.libraryFiles != null) {
return new LibrarySourcesConfig(project, moduleId, Arrays.asList(arguments.libraryFiles), ecmaVersion);
return new LibrarySourcesConfig(project, moduleId, Arrays.asList(arguments.libraryFiles), ecmaVersion, arguments.sourcemap);
}
else {
// lets discover the JS library definitions on the classpath
return new ClassPathLibraryDefintionsConfig(project, moduleId, ecmaVersion);
return new ClassPathLibraryDefintionsConfig(project, moduleId, ecmaVersion, arguments.sourcemap);
}
}
}
@@ -37,6 +37,9 @@ public class K2JSCompilerArguments extends CompilerArguments {
@Argument(value = "sourceFiles", description = "Source files (dir or file)")
public String[] sourceFiles;
@Argument(value = "sourcemap", description = "Generate SourceMap")
public boolean sourcemap;
@Argument(value = "target", description = "Generate js files for specific ECMA version (3 or 5, default ECMA 3)")
public String target;
@@ -52,7 +52,7 @@ class JSDeclarationsCacheProvider extends DeclarationsCacheProvider {
LibrarySourcesConfig config = new LibrarySourcesConfig(
project, "default",
KotlinFrameworkDetector.getLibLocationAndTargetForProject(project).first,
EcmaVersion.defaultVersion());
EcmaVersion.defaultVersion(), false);
AnalyzeExhaust analyzeExhaust = AnalyzerFacadeForJS.analyzeFiles(
JetFilesProvider.getInstance(project).allInScope(GlobalSearchScope.allScope(project)),
@@ -18,12 +18,13 @@ package org.jetbrains.jet.plugin.project;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.plugin.framework.KotlinFrameworkDetector;
import org.jetbrains.k2js.config.EcmaVersion;
import org.jetbrains.k2js.config.LibrarySourcesConfig;
import static org.jetbrains.jet.plugin.framework.KotlinFrameworkDetector.getLibLocationAndTargetForProject;
public final class IDEAConfig extends LibrarySourcesConfig {
public IDEAConfig(@NotNull Project project) {
super(project, "default", KotlinFrameworkDetector.getLibLocationAndTargetForProject(project).first, EcmaVersion.defaultVersion());
super(project, "default", getLibLocationAndTargetForProject(project).first, EcmaVersion.defaultVersion(), false);
}
}
}
@@ -18,7 +18,6 @@ package org.jetbrains.k2js.test.utils;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import com.google.dart.compiler.backend.js.ast.JsProgram;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.psi.PsiFile;
@@ -32,11 +31,13 @@ import org.jetbrains.k2js.config.Config;
import org.jetbrains.k2js.config.EcmaVersion;
import org.jetbrains.k2js.facade.K2JSTranslator;
import org.jetbrains.k2js.facade.MainCallParameters;
import org.jetbrains.k2js.generate.CodeGenerator;
import org.jetbrains.k2js.test.config.TestConfigFactory;
import org.jetbrains.k2js.utils.JetFileUtils;
import java.io.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.util.List;
@@ -70,6 +71,7 @@ public final class TranslationUtils {
Predicate<PsiFile> filesWithCode = new Predicate<PsiFile>() {
@Override
public boolean apply(@javax.annotation.Nullable PsiFile file) {
assert file != null;
return isFileWithCode((JetFile) file);
}
};
@@ -102,14 +104,8 @@ public final class TranslationUtils {
@NotNull MainCallParameters mainCallParameters,
@NotNull EcmaVersion version, TestConfigFactory configFactory) throws Exception {
List<JetFile> psiFiles = createPsiFileList(inputFiles, project);
JsProgram program = new K2JSTranslator(getConfig(project, version, configFactory)).generateProgram(psiFiles, mainCallParameters);
FileWriter writer = new FileWriter(new File(outputFile));
try {
writer.write(CodeGenerator.generateProgramToString(program));
}
finally {
writer.close();
}
K2JSTranslator translator = new K2JSTranslator(getConfig(project, version, configFactory));
FileUtil.writeToFile(new File(outputFile), translator.generateProgramCode(psiFiles, mainCallParameters));
}
@NotNull
Binary file not shown.
Binary file not shown.
@@ -30,8 +30,8 @@ public class ClassPathLibraryDefintionsConfig extends Config {
@NotNull
public static final String META_INF_SERVICES_FILE = "META-INF/services/org.jetbrains.kotlin.js.libraryDefinitions";
public ClassPathLibraryDefintionsConfig(@NotNull Project project, @NotNull String moduleId, @NotNull EcmaVersion version) {
super(project, moduleId, version);
public ClassPathLibraryDefintionsConfig(@NotNull Project project, @NotNull String moduleId, @NotNull EcmaVersion version, boolean sourcemap) {
super(project, moduleId, version, sourcemap);
}
@NotNull
@@ -149,10 +149,21 @@ public abstract class Config {
@NotNull
private final String moduleId;
private final boolean sourcemap;
public Config(@NotNull Project project, @NotNull String moduleId, @NotNull EcmaVersion ecmaVersion) {
this(project, moduleId, ecmaVersion, false);
}
public Config(@NotNull Project project, @NotNull String moduleId, @NotNull EcmaVersion ecmaVersion, boolean sourcemap) {
this.project = project;
this.target = ecmaVersion;
this.moduleId = moduleId;
this.sourcemap = sourcemap;
}
public boolean isSourcemap() {
return sourcemap;
}
@NotNull
@@ -1,83 +0,0 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.k2js.config;
import com.google.common.collect.Lists;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.io.FileUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.k2js.utils.JetFileUtils;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
public class LibrarySourceDirectoriesConfig extends Config {
@NotNull
protected final String[] directories;
public LibrarySourceDirectoriesConfig(@NotNull Project project, @NotNull String moduleId, @NotNull String[] directories, @NotNull EcmaVersion ecmaVersion) {
super(project, moduleId, ecmaVersion);
this.directories = directories;
}
@NotNull
@Override
public List<JetFile> generateLibFiles() {
try {
List<JetFile> results = Lists.newArrayList();
for (String directory : directories) {
File rootDir = new File(directory);
results.addAll(traverseDirectory(rootDir, rootDir));
}
return results;
}
catch (IOException e) {
System.out.println("Caught: " + e);
e.printStackTrace();
return Collections.emptyList();
}
}
@NotNull
private List<JetFile> traverseDirectory(@NotNull File rootDir, @NotNull File dir) throws IOException {
File[] files = dir.listFiles();
File[] children = dir.listFiles();
List<JetFile> result = Lists.newArrayList();
if (children != null && children.length > 0) {
for (File child : children) {
if (child.isDirectory()) {
List<JetFile> childFiles = traverseDirectory(rootDir, child);
result.addAll(childFiles);
}
else {
String name = child.getName();
if (name.toLowerCase().endsWith(".kt")) {
String text = FileUtil.loadFile(child);
//String path = FileUtil.getRelativePath(directoryFile, child);
String path = child.getPath();
JetFile jfile = JetFileUtils.createPsiFile(path, text, getProject());
result.add(jfile);
}
}
}
}
return result;
}
}
@@ -47,11 +47,14 @@ public class LibrarySourcesConfig extends Config {
@NotNull
private final List<String> files;
public LibrarySourcesConfig(@NotNull Project project,
public LibrarySourcesConfig(
@NotNull Project project,
@NotNull String moduleId,
@NotNull List<String> files,
@NotNull EcmaVersion ecmaVersion) {
super(project, moduleId, ecmaVersion);
@NotNull EcmaVersion ecmaVersion,
boolean sourcemap
) {
super(project, moduleId, ecmaVersion, sourcemap);
this.files = files;
}
@@ -16,12 +16,16 @@
package org.jetbrains.k2js.facade;
import com.google.dart.compiler.backend.js.JsSourceGenerationVisitor;
import com.google.dart.compiler.backend.js.ast.JsProgram;
import com.google.dart.compiler.util.TextOutputImpl;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.io.FileUtil;
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.js.compiler.SourceMapBuilder;
import org.jetbrains.k2js.analyze.AnalyzerFacadeForJS;
import org.jetbrains.k2js.config.Config;
import org.jetbrains.k2js.facade.exceptions.TranslationException;
@@ -30,11 +34,10 @@ import org.jetbrains.k2js.utils.JetFileUtils;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static org.jetbrains.k2js.facade.FacadeUtils.parseString;
import static org.jetbrains.k2js.generate.CodeGenerator.generateProgramToString;
/**
* An entry point of translator.
@@ -49,8 +52,14 @@ public final class K2JSTranslator {
@NotNull String outputPath,
@NotNull Config config) throws TranslationException, IOException {
K2JSTranslator translator = new K2JSTranslator(config);
String programCode = translator.generateProgramCode(files, mainCall);
FileUtil.writeToFile(new File(outputPath), programCode);
File outFile = new File(outputPath);
TextOutputImpl output = new TextOutputImpl();
SourceMapBuilder sourceMapBuilder = config.isSourcemap() ? new SourceMapBuilder(outFile.getName(), output, new SourceMapBuilderConsumer()) : null;
String programCode = translator.generateProgramCode(files, mainCall, output, sourceMapBuilder);
FileUtil.writeToFile(outFile, programCode);
if (sourceMapBuilder != null) {
FileUtil.writeToFile(new File(outFile.getParentFile(), sourceMapBuilder.getOutFilename()), sourceMapBuilder.build());
}
}
@NotNull
@@ -72,15 +81,26 @@ public final class K2JSTranslator {
@NotNull
public String generateProgramCode(@NotNull JetFile file, @NotNull MainCallParameters mainCallParameters) throws TranslationException {
JsProgram program = generateProgram(Arrays.asList(file), mainCallParameters);
return generateProgramToString(program);
return generateProgramCode(Collections.singletonList(file), mainCallParameters);
}
@NotNull
public String generateProgramCode(@NotNull List<JetFile> files, @NotNull MainCallParameters mainCallParameters)
throws TranslationException {
return generateProgramCode(files, mainCallParameters, new TextOutputImpl(), null);
}
@NotNull
public String generateProgramCode(
@NotNull List<JetFile> files,
@NotNull MainCallParameters mainCallParameters,
@NotNull TextOutputImpl output,
@Nullable SourceMapBuilder sourceMapBuilder
) throws TranslationException {
JsProgram program = generateProgram(files, mainCallParameters);
return generateProgramToString(program);
JsSourceGenerationVisitor sourceGenerator = new JsSourceGenerationVisitor(output, sourceMapBuilder);
program.traverse(sourceGenerator, null);
return output.toString();
}
@NotNull
@@ -95,4 +115,4 @@ public final class K2JSTranslator {
private Project getProject() {
return config.getProject();
}
}
}
@@ -0,0 +1,41 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.k2js.facade;
import com.intellij.openapi.editor.Document;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.util.PairConsumer;
import org.jetbrains.js.compiler.SourceMapBuilder;
class SourceMapBuilderConsumer implements PairConsumer<SourceMapBuilder, Object> {
@Override
public void consume(SourceMapBuilder builder, Object sourceInfo) {
if (!(sourceInfo instanceof PsiElement)) {
return;
}
PsiElement element = (PsiElement) sourceInfo;
PsiFile file = element.getContainingFile();
int offset = element.getNode().getStartOffset();
Document document = file.getViewProvider().getDocument();
assert document != null;
int line = document.getLineNumber(offset);
int column = offset - document.getLineStartOffset(line);
builder.addMapping(file.getViewProvider().getVirtualFile().getPath(), line, column);
}
}
@@ -1,35 +0,0 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.k2js.generate;
import com.google.dart.compiler.backend.js.JsSourceGenerationVisitor;
import com.google.dart.compiler.backend.js.ast.JsProgram;
import com.google.dart.compiler.util.TextOutputImpl;
import org.jetbrains.annotations.NotNull;
public final class CodeGenerator {
private CodeGenerator() {
}
@NotNull
public static String generateProgramToString(@NotNull JsProgram program) {
TextOutputImpl output = new TextOutputImpl();
JsSourceGenerationVisitor sourceGenerator = new JsSourceGenerationVisitor(output);
program.traverse(sourceGenerator, null);
return output.toString();
}
}
@@ -121,8 +121,7 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
@NotNull TranslationContext context) {
JetExpression returnedExpression = jetReturnExpression.getReturnedExpression();
if (returnedExpression != null) {
JsExpression jsExpression = translateAsExpression(returnedExpression, context);
return new JsReturn(jsExpression);
return new JsReturn(translateAsExpression(returnedExpression, context));
}
return new JsReturn();
}
@@ -88,7 +88,9 @@ public final class Translation {
//NOTE: use with care
@NotNull
public static JsNode doTranslateExpression(JetExpression expression, TranslationContext context) {
return expression.accept(new ExpressionVisitor(), context);
JsNode jsNode = expression.accept(new ExpressionVisitor(), context);
jsNode.setSourceInfo(expression);
return jsNode;
}
@NotNull
@@ -16,19 +16,13 @@
package org.jetbrains.k2js.translate.utils;
import com.google.common.collect.Lists;
import com.google.dart.compiler.backend.js.ast.JsExpression;
import com.google.dart.compiler.common.SourceInfo;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.resolve.BindingContext;
import java.util.List;
public final class ErrorReportingUtils {
private ErrorReportingUtils() {
}
@@ -66,17 +60,4 @@ public final class ErrorReportingUtils {
@NotNull BindingContext bindingContext) {
throw reportErrorWithLocation(e, DiagnosticUtils.atLocation(bindingContext, descriptor));
}
@NotNull
public static String atLocation(@Nullable JsExpression expression, @NotNull List<JsExpression> arguments) {
List<JsExpression> list = Lists.newArrayList(expression);
list.addAll(arguments);
for (JsExpression value : arguments) {
SourceInfo info = value.getSourceInfo();
if (info != null) {
return "at " + info.getSource().getUri() + " " + info.getLine() + ":" + info.getColumn();
}
}
return "at unknown location";
}
}
@@ -45,14 +45,14 @@ public final class LastExpressionMutator {
if (node instanceof JsIf) {
return applyToIf((JsIf) node);
}
if (node instanceof JsExprStmt) {
return applyToStatement((JsExprStmt) node);
if (node instanceof JsExpressionStatement) {
return applyToStatement((JsExpressionStatement) node);
}
return mutator.mutate(node);
}
@NotNull
private JsNode applyToStatement(@NotNull JsExprStmt node) {
private JsNode applyToStatement(@NotNull JsExpressionStatement node) {
return convertToStatement(apply(node.getExpression()));
}