initial changes
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2000-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.analyze;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.Configuration;
|
||||
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
|
||||
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
import org.jetbrains.jet.lang.psi.JetPsiFactory;
|
||||
import org.jetbrains.jet.lang.resolve.*;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
|
||||
import org.jetbrains.k2js.config.Config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class Analyzer {
|
||||
|
||||
private Analyzer() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static BindingContext analyzeFilesAndCheckErrors(@NotNull List<JetFile> files,
|
||||
@NotNull Config config) {
|
||||
BindingContext bindingContext = analyzeFiles(files, config);
|
||||
checkForErrors(withJsLibAdded(files, config), bindingContext);
|
||||
return bindingContext;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static BindingContext analyzeFiles(@NotNull List<JetFile> files,
|
||||
@NotNull Config config) {
|
||||
Project project = config.getProject();
|
||||
return AnalyzingUtils.analyzeFiles(project,
|
||||
JsConfiguration.jsLibConfiguration(project),
|
||||
withJsLibAdded(files, config),
|
||||
notLibFiles(config.getLibFiles()),
|
||||
JetControlFlowDataTraceFactory.EMPTY);
|
||||
}
|
||||
|
||||
private static void checkForErrors(@NotNull List<JetFile> allFiles, @NotNull BindingContext bindingContext) {
|
||||
AnalyzingUtils.throwExceptionOnErrors(bindingContext);
|
||||
for (JetFile file : allFiles) {
|
||||
AnalyzingUtils.checkForSyntacticErrors(file);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: use some mechanism to avoid this
|
||||
//TODO: move method somewhere
|
||||
@NotNull
|
||||
public static List<JetFile> withJsLibAdded(@NotNull List<JetFile> files, @NotNull Config config) {
|
||||
List<JetFile> allFiles = new ArrayList<JetFile>();
|
||||
allFiles.addAll(files);
|
||||
allFiles.addAll(config.getLibFiles());
|
||||
return allFiles;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Predicate<PsiFile> notLibFiles(@NotNull final List<JetFile> jsLibFiles) {
|
||||
return new Predicate<PsiFile>() {
|
||||
@Override
|
||||
public boolean apply(@Nullable PsiFile file) {
|
||||
assert file instanceof JetFile;
|
||||
@SuppressWarnings("UnnecessaryLocalVariable") boolean notLibFile = !jsLibFiles.contains(file);
|
||||
return notLibFile;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static final class JsConfiguration implements Configuration {
|
||||
|
||||
@NotNull
|
||||
private Project project;
|
||||
|
||||
public static JsConfiguration jsLibConfiguration(@NotNull Project project) {
|
||||
return new JsConfiguration(project);
|
||||
}
|
||||
|
||||
private JsConfiguration(@NotNull Project project) {
|
||||
this.project = project;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDefaultImports(@NotNull BindingTrace trace, @NotNull WritableScope rootScope,
|
||||
@NotNull Importer importer) {
|
||||
ImportsResolver.ImportResolver importResolver = new ImportsResolver.ImportResolver(trace, true);
|
||||
importResolver.processImportReference(JetPsiFactory.createImportDirective(project, "js.*"), rootScope, importer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void extendNamespaceScope(@NotNull BindingTrace trace, @NotNull NamespaceDescriptor namespaceDescriptor,
|
||||
@NotNull WritableScope namespaceMemberScope) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2000-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.config;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
* <p/>
|
||||
* Base class reprenting a configuration of translator.
|
||||
*/
|
||||
public abstract class Config {
|
||||
|
||||
@NotNull
|
||||
public abstract Project getProject();
|
||||
|
||||
@NotNull
|
||||
public abstract List<JetFile> getLibFiles();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2000-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.config;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class IDEAConfig extends Config {
|
||||
|
||||
@NotNull
|
||||
private final Project project;
|
||||
|
||||
public IDEAConfig(@NotNull Project project) {
|
||||
this.project = project;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Project getProject() {
|
||||
return project;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<JetFile> getLibFiles() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright 2000-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.config;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import core.Dummy;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.compiler.JetCoreEnvironment;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
import org.jetbrains.k2js.utils.JetFileUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
//TODO: review/refactor
|
||||
public final class TestConfig extends Config {
|
||||
|
||||
//TODO: provide some generic way to get the files of the project
|
||||
@NotNull
|
||||
private static final List<String> LIB_FILE_NAMES = Arrays.asList(
|
||||
"/core/annotations.kt",
|
||||
"/jquery/common.kt",
|
||||
"/jquery/ui.kt",
|
||||
"/core/javautil.kt",
|
||||
"/core/javalang.kt",
|
||||
"/core/core.kt",
|
||||
"/core/math.kt",
|
||||
"/core/json.kt",
|
||||
"/raphael/raphael.kt",
|
||||
"/html5/canvas.kt",
|
||||
"/html5/files.kt",
|
||||
"/html5/image.kt"
|
||||
);
|
||||
|
||||
@NotNull
|
||||
private static JetCoreEnvironment getTestEnvironment() {
|
||||
if (testOnlyEnvironment == null) {
|
||||
testOnlyEnvironment = new JetCoreEnvironment(new Disposable() {
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
});
|
||||
}
|
||||
return testOnlyEnvironment;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static /*var*/ JetCoreEnvironment testOnlyEnvironment = null;
|
||||
|
||||
|
||||
@Nullable
|
||||
private /*var*/ List<JetFile> jsLibFiles = null;
|
||||
|
||||
public TestConfig() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Project getProject() {
|
||||
return getTestEnvironment().getProject();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<JetFile> initLibFiles(@NotNull Project project) {
|
||||
List<JetFile> libFiles = new ArrayList<JetFile>();
|
||||
for (String libFileName : LIB_FILE_NAMES) {
|
||||
JetFile file = null;
|
||||
//TODO: close stream?
|
||||
InputStream stream = Dummy.class.getResourceAsStream(libFileName);
|
||||
try {
|
||||
String text = readString(stream);
|
||||
file = JetFileUtils.createPsiFile(libFileName, text, project);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
libFiles.add(file);
|
||||
}
|
||||
return libFiles;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<JetFile> getLibFiles() {
|
||||
if (jsLibFiles == null) {
|
||||
jsLibFiles = initLibFiles(getProject());
|
||||
}
|
||||
return jsLibFiles;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String readString(@NotNull InputStream is) throws IOException {
|
||||
char[] buf = new char[2048];
|
||||
Reader r = new InputStreamReader(is, "UTF-8");
|
||||
StringBuilder s = new StringBuilder();
|
||||
while (true) {
|
||||
int n = r.read(buf);
|
||||
if (n < 0)
|
||||
break;
|
||||
s.append(buf, 0, n);
|
||||
}
|
||||
return s.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright 2000-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.google.dart.compiler.backend.js.ast.JsProgram;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.types.JetStandardLibrary;
|
||||
import org.jetbrains.jet.plugin.JetMainDetector;
|
||||
import org.jetbrains.k2js.analyze.Analyzer;
|
||||
import org.jetbrains.k2js.config.Config;
|
||||
import org.jetbrains.k2js.config.IDEAConfig;
|
||||
import org.jetbrains.k2js.config.TestConfig;
|
||||
import org.jetbrains.k2js.generate.CodeGenerator;
|
||||
import org.jetbrains.k2js.translate.general.Translation;
|
||||
import org.jetbrains.k2js.utils.GenerationUtils;
|
||||
import org.jetbrains.k2js.utils.JetFileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getNamespaceName;
|
||||
import static org.jetbrains.k2js.utils.JetFileUtils.createPsiFileList;
|
||||
|
||||
//TODO: clean up the code
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
* <p/>
|
||||
* An entry point of translator.
|
||||
*/
|
||||
public final class K2JSTranslator {
|
||||
|
||||
public static void translateWithCallToMainAndSaveToFile(@NotNull List<JetFile> files,
|
||||
@NotNull String outputPath,
|
||||
@NotNull Project project) throws Exception {
|
||||
K2JSTranslator translator = new K2JSTranslator(new IDEAConfig(project));
|
||||
String programCode = translator.generateProgramCode(files) + "\n";
|
||||
JetFile fileWithMain = JetMainDetector.getFileWithMain(files);
|
||||
if (fileWithMain == null) {
|
||||
throw new RuntimeException("No file with main detected.");
|
||||
}
|
||||
String callToMain = translator.generateCallToMain(fileWithMain, "");
|
||||
FileWriter writer = new FileWriter(new File(outputPath));
|
||||
writer.write(programCode + callToMain);
|
||||
writer.close();
|
||||
}
|
||||
|
||||
public static void testTranslateFile(@NotNull String inputFile,
|
||||
@NotNull String outputFile) throws Exception {
|
||||
testTranslateFiles(Collections.singletonList(inputFile), outputFile);
|
||||
}
|
||||
|
||||
public static void testTranslateFiles(@NotNull List<String> inputFiles,
|
||||
@NotNull String outputFile) throws Exception {
|
||||
K2JSTranslator translator = new K2JSTranslator(new TestConfig());
|
||||
List<JetFile> psiFiles = createPsiFileList(inputFiles, translator.getProject());
|
||||
JsProgram program = translator.generateProgram(psiFiles);
|
||||
saveProgramToFile(outputFile, program);
|
||||
}
|
||||
|
||||
private static void saveProgramToFile(@NotNull String outputFile, @NotNull JsProgram program) throws IOException {
|
||||
CodeGenerator generator = new CodeGenerator();
|
||||
generator.generateToFile(program, new File(outputFile));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Config config;
|
||||
|
||||
|
||||
public K2JSTranslator(@NotNull Config config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
//TODO: refactor
|
||||
@NotNull
|
||||
public String translateStringWithCallToMain(@NotNull String programText, @NotNull String argumentsString) {
|
||||
JetFile file = JetFileUtils.createPsiFile("test", programText, getProject());
|
||||
String programCode = generateProgramCode(file) + "\n";
|
||||
String flushOutput = "Kotlin.System.flush();\n";
|
||||
String callToMain = generateCallToMain(file, argumentsString);
|
||||
String programOutput = "Kotlin.System.output();\n";
|
||||
return programCode + flushOutput + callToMain + programOutput;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String generateProgramCode(@NotNull JetFile psiFile) {
|
||||
JsProgram program = generateProgram(Arrays.asList(psiFile));
|
||||
CodeGenerator generator = new CodeGenerator();
|
||||
return generator.generateToString(program);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String generateProgramCode(@NotNull List<JetFile> files) {
|
||||
JsProgram program = generateProgram(files);
|
||||
CodeGenerator generator = new CodeGenerator();
|
||||
return generator.generateToString(program);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public BindingContext analyzeProgramCode(@NotNull String programText) {
|
||||
JetFile file = JetFileUtils.createPsiFile("test", programText, getProject());
|
||||
return Analyzer.analyzeFiles(Arrays.asList(file), config);
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
private JsProgram generateProgram(@NotNull List<JetFile> filesToTranslate) {
|
||||
JetStandardLibrary.initialize(config.getProject());
|
||||
BindingContext bindingContext = Analyzer.analyzeFilesAndCheckErrors(filesToTranslate, config);
|
||||
return Translation.generateAst(bindingContext, Analyzer.withJsLibAdded(filesToTranslate, config));
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
public String generateCallToMain(@NotNull JetFile file, @NotNull String argumentString) {
|
||||
String namespaceName = getNamespaceName(file);
|
||||
List<String> arguments = parseString(argumentString);
|
||||
return GenerationUtils.generateCallToMain(namespaceName, arguments);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<String> parseString(@NotNull String argumentString) {
|
||||
List<String> result = new ArrayList<String>();
|
||||
StringTokenizer stringTokenizer = new StringTokenizer(argumentString);
|
||||
while (stringTokenizer.hasMoreTokens()) {
|
||||
result.add(stringTokenizer.nextToken());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Project getProject() {
|
||||
return config.getProject();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2000-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 org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.k2js.config.TestConfig;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* User: Natalia.Ukhorskaya
|
||||
* Date: 2/9/12
|
||||
* Time: 7:49 PM
|
||||
*/
|
||||
|
||||
public class K2JSTranslatorUtils {
|
||||
@SuppressWarnings("FieldCanBeLocal")
|
||||
private static String EXCEPTION = "exception=";
|
||||
|
||||
@Nullable
|
||||
public String translateToJS(@NotNull String code, @NotNull String arguments) {
|
||||
try {
|
||||
return generateJSCode(code, arguments);
|
||||
} catch (AssertionError e) {
|
||||
reportException(e);
|
||||
return EXCEPTION + "Translation error.";
|
||||
} catch (UnsupportedOperationException e) {
|
||||
reportException(e);
|
||||
return EXCEPTION + "Unsupported feature.";
|
||||
} catch (Throwable e) {
|
||||
reportException(e);
|
||||
return EXCEPTION + "Unexpected exception.";
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public BindingContext getBindingContext(@NotNull String programText) {
|
||||
try {
|
||||
K2JSTranslator k2JSTranslator = new K2JSTranslator(new TestConfig());
|
||||
return k2JSTranslator.analyzeProgramCode(programText);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
reportException(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String generateJSCode(@NotNull String code, @NotNull String arguments) {
|
||||
String generatedCode = (new K2JSTranslator(new TestConfig())).translateStringWithCallToMain(code, arguments);
|
||||
return generatedCode;
|
||||
}
|
||||
|
||||
private void reportException(@NotNull Throwable e) {
|
||||
System.out.println("Exception in translateToJS!!!");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2000-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.generate;
|
||||
|
||||
import com.google.dart.compiler.backend.js.JsSourceGenerationVisitor;
|
||||
import com.google.dart.compiler.backend.js.ast.JsProgram;
|
||||
import com.google.dart.compiler.util.DefaultTextOutput;
|
||||
import com.google.dart.compiler.util.TextOutput;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author Pavel.Talanov
|
||||
*/
|
||||
public final class CodeGenerator {
|
||||
|
||||
@NotNull
|
||||
private final TextOutput output = new DefaultTextOutput(false);
|
||||
|
||||
public CodeGenerator() {
|
||||
}
|
||||
|
||||
public void generateToFile(@NotNull JsProgram program, @NotNull File file) throws IOException {
|
||||
generateCode(program);
|
||||
FileWriter writer = new FileWriter(file);
|
||||
writer.write(output.toString());
|
||||
writer.close();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String generateToString(@NotNull JsProgram program) {
|
||||
generateCode(program);
|
||||
return output.toString();
|
||||
}
|
||||
|
||||
private void generateCode(@NotNull JsProgram program) {
|
||||
JsSourceGenerationVisitor sourceGenerator =
|
||||
new JsSourceGenerationVisitor(output);
|
||||
program.traverse(sourceGenerator, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.context;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsName;
|
||||
import com.google.dart.compiler.backend.js.ast.JsNameRef;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
|
||||
public class Aliaser {
|
||||
|
||||
public static Aliaser newInstance() {
|
||||
return new Aliaser();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final Map<DeclarationDescriptor, JsName> aliasesForDescriptors = new HashMap<DeclarationDescriptor, JsName>();
|
||||
@NotNull
|
||||
private final Map<DeclarationDescriptor, Stack<JsName>> aliasesForThis
|
||||
= new HashMap<DeclarationDescriptor, Stack<JsName>>();
|
||||
|
||||
private Aliaser() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsNameRef getAliasForThis(@NotNull DeclarationDescriptor descriptor) {
|
||||
Stack<JsName> aliasStack = aliasesForThis.get(descriptor.getOriginal());
|
||||
assert !aliasStack.empty();
|
||||
JsName aliasName = aliasStack.peek();
|
||||
assert aliasName != null : "This " + descriptor.getOriginal() + " doesn't have an alias.";
|
||||
return aliasName.makeRef();
|
||||
}
|
||||
|
||||
public void setAliasForThis(@NotNull DeclarationDescriptor descriptor, @NotNull JsName alias) {
|
||||
Stack<JsName> aliasStack = aliasesForThis.get(descriptor.getOriginal());
|
||||
if (aliasStack == null) {
|
||||
aliasStack = new Stack<JsName>();
|
||||
aliasesForThis.put(descriptor, aliasStack);
|
||||
}
|
||||
aliasStack.push(alias);
|
||||
}
|
||||
|
||||
public void removeAliasForThis(@NotNull DeclarationDescriptor descriptor) {
|
||||
Stack<JsName> aliasStack = aliasesForThis.get(descriptor.getOriginal());
|
||||
assert !aliasStack.empty();
|
||||
aliasStack.pop();
|
||||
if (aliasStack.empty()) {
|
||||
aliasesForThis.put(descriptor, null);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasAliasForThis(@NotNull DeclarationDescriptor descriptor) {
|
||||
Stack<JsName> aliasStack = aliasesForThis.get(descriptor.getOriginal());
|
||||
if (aliasStack == null) {
|
||||
return false;
|
||||
}
|
||||
return (!aliasStack.empty());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsName getAliasForDeclaration(@NotNull DeclarationDescriptor declaration) {
|
||||
JsName alias = aliasesForDescriptors.get(declaration.getOriginal());
|
||||
assert alias != null : "Use has alias for declaration to check.";
|
||||
return alias;
|
||||
}
|
||||
|
||||
public void setAliasForDescriptor(@NotNull DeclarationDescriptor declaration, @NotNull JsName alias) {
|
||||
assert (!hasAliasForDeclaration(declaration.getOriginal())) : "This declaration already has an alias!";
|
||||
aliasesForDescriptors.put(declaration.getOriginal(), alias);
|
||||
}
|
||||
|
||||
public void removeAliasForDescriptor(@NotNull DeclarationDescriptor declaration) {
|
||||
assert (hasAliasForDeclaration(declaration.getOriginal())) : "This declaration does not has an alias!";
|
||||
aliasesForDescriptors.remove(declaration.getOriginal());
|
||||
}
|
||||
|
||||
public boolean hasAliasForDeclaration(@NotNull DeclarationDescriptor declaration) {
|
||||
return aliasesForDescriptors.containsKey(declaration.getOriginal());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.context;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.*;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class DynamicContext {
|
||||
|
||||
@NotNull
|
||||
public static DynamicContext rootContext(@NotNull NamingScope rootScope, @NotNull JsBlock globalBlock) {
|
||||
return new DynamicContext(rootScope, rootScope, globalBlock);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static DynamicContext contextWithScope(@NotNull NamingScope scope) {
|
||||
return new DynamicContext(scope, scope, new JsBlock());
|
||||
}
|
||||
|
||||
//TODO: current/block scope logic unclear. is it necessary?
|
||||
@NotNull
|
||||
private NamingScope currentScope;
|
||||
|
||||
@NotNull
|
||||
private NamingScope blockScope;
|
||||
|
||||
@NotNull
|
||||
private JsBlock currentBlock;
|
||||
|
||||
private DynamicContext(@NotNull NamingScope scope, @NotNull NamingScope blockScope, @NotNull JsBlock block) {
|
||||
this.currentScope = scope;
|
||||
this.currentBlock = block;
|
||||
this.blockScope = blockScope;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public DynamicContext innerScope(@NotNull JsScope scope) {
|
||||
return new DynamicContext(currentScope.innerScope(scope), blockScope, currentBlock);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public NamingScope getScope() {
|
||||
return blockScope;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public DynamicContext innerBlock(@NotNull JsBlock block) {
|
||||
return new DynamicContext(currentScope, currentScope, block);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public TemporaryVariable declareTemporary(@NotNull JsExpression initExpression) {
|
||||
JsName temporaryName = blockScope.declareTemporary();
|
||||
JsVars temporaryDeclaration = AstUtil.newVar(temporaryName, null);
|
||||
jsBlock().addVarDeclaration(temporaryDeclaration);
|
||||
return new TemporaryVariable(temporaryName, initExpression);
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
public JsScope jsScope() {
|
||||
return currentScope.jsScope();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsBlock jsBlock() {
|
||||
return currentBlock;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.context;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsName;
|
||||
import com.google.dart.compiler.backend.js.ast.JsNameRef;
|
||||
import com.google.dart.compiler.backend.js.ast.JsScope;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
* <p/>
|
||||
* Encapuslates different types of constants and naming conventions.
|
||||
*/
|
||||
public final class Namer {
|
||||
|
||||
private static final String INITIALIZE_METHOD_NAME = "initialize";
|
||||
private static final String CLASS_OBJECT_NAME = "Class";
|
||||
private static final String TRAIT_OBJECT_NAME = "Trait";
|
||||
private static final String NAMESPACE_OBJECT_NAME = "Namespace";
|
||||
private static final String OBJECT_OBJECT_NAME = "object";
|
||||
private static final String SETTER_PREFIX = "set_";
|
||||
private static final String GETTER_PREFIX = "get_";
|
||||
private static final String BACKING_FIELD_PREFIX = "$";
|
||||
private static final String SUPER_METHOD_NAME = "super_init";
|
||||
private static final String KOTLIN_OBJECT_NAME = "Kotlin";
|
||||
private static final String ANONYMOUS_NAMESPACE = "Anonymous";
|
||||
private static final String RECEIVER_PARAMETER_NAME = "receiver";
|
||||
|
||||
@NotNull
|
||||
public static String getReceiverParameterName() {
|
||||
return RECEIVER_PARAMETER_NAME;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getAnonymousNamespaceName() {
|
||||
return ANONYMOUS_NAMESPACE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsNameRef initializeMethodReference() {
|
||||
return AstUtil.newQualifiedNameRef(INITIALIZE_METHOD_NAME);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String superMethodName() {
|
||||
return SUPER_METHOD_NAME;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String nameForClassesVariable() {
|
||||
return "classes";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getNameForAccessor(@NotNull String propertyName, boolean isGetter) {
|
||||
if (isGetter) {
|
||||
return getNameForGetter(propertyName);
|
||||
} else {
|
||||
return getNameForSetter(propertyName);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getKotlinBackingFieldName(String propertyName) {
|
||||
return getNameWithPrefix(propertyName, BACKING_FIELD_PREFIX);
|
||||
}
|
||||
|
||||
public static String getNameForGetter(String propertyName) {
|
||||
return getNameWithPrefix(propertyName, GETTER_PREFIX);
|
||||
}
|
||||
|
||||
public static String getNameForSetter(String propertyName) {
|
||||
return getNameWithPrefix(propertyName, SETTER_PREFIX);
|
||||
}
|
||||
|
||||
private static String getNameWithPrefix(String name, String prefix) {
|
||||
return prefix + name;
|
||||
}
|
||||
|
||||
public static Namer newInstance(@NotNull JsScope rootScope) {
|
||||
return new Namer(rootScope);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final JsName kotlinName;
|
||||
@NotNull
|
||||
private final JsScope kotlinScope;
|
||||
@NotNull
|
||||
private final JsName className;
|
||||
@NotNull
|
||||
private final JsName traitName;
|
||||
@NotNull
|
||||
private final JsName namespaceName;
|
||||
@NotNull
|
||||
private final JsName objectName;
|
||||
|
||||
private Namer(@NotNull JsScope rootScope) {
|
||||
kotlinName = rootScope.declareName(KOTLIN_OBJECT_NAME);
|
||||
kotlinScope = new JsScope(rootScope, "Kotlin standard object");
|
||||
traitName = kotlinScope.declareName(TRAIT_OBJECT_NAME);
|
||||
namespaceName = kotlinScope.declareName(NAMESPACE_OBJECT_NAME);
|
||||
className = kotlinScope.declareName(CLASS_OBJECT_NAME);
|
||||
objectName = kotlinScope.declareName(OBJECT_OBJECT_NAME);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsNameRef classCreationMethodReference() {
|
||||
return kotlin(createMethodReference(className));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsNameRef traitCreationMethodReference() {
|
||||
return kotlin(createMethodReference(traitName));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsNameRef namespaceCreationMethodReference() {
|
||||
return kotlin(createMethodReference(namespaceName));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsNameRef objectCreationMethodReference() {
|
||||
return kotlin(createMethodReference(objectName));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsNameRef createMethodReference(@NotNull JsName name) {
|
||||
JsNameRef qualifier = name.makeRef();
|
||||
JsNameRef reference = AstUtil.newQualifiedNameRef("create");
|
||||
AstUtil.setQualifier(reference, qualifier);
|
||||
return reference;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsNameRef kotlin(@NotNull JsNameRef reference) {
|
||||
JsNameRef kotlinReference = kotlinName.makeRef();
|
||||
AstUtil.setQualifier(reference, kotlinReference);
|
||||
return reference;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsNameRef kotlinObject() {
|
||||
return kotlinName.makeRef();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsNameRef isOperationReference() {
|
||||
return kotlin(AstUtil.newQualifiedNameRef("isType"));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
/*package*/ JsScope getKotlinScope() {
|
||||
return kotlinScope;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.context;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsName;
|
||||
import com.google.dart.compiler.backend.js.ast.JsScope;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
* <p/>
|
||||
* Basically a wrapper around JsScope.
|
||||
*/
|
||||
public final class NamingScope {
|
||||
|
||||
@NotNull
|
||||
public static NamingScope rootScope(@NotNull JsScope rootScope) {
|
||||
return new NamingScope(rootScope);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final JsScope scope;
|
||||
|
||||
private NamingScope(@NotNull JsScope correspondingScope) {
|
||||
this.scope = correspondingScope;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public NamingScope innerScope(@NotNull String scopeName) {
|
||||
JsScope innerJsScope = new JsScope(jsScope(), scopeName);
|
||||
return new NamingScope(innerJsScope);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public NamingScope innerScope(@NotNull JsScope correspondingScope) {
|
||||
return new NamingScope(correspondingScope);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
/*package*/ JsName declareUnobfuscatableName(@NotNull String name) {
|
||||
JsName declaredName = scope.declareName(name);
|
||||
declaredName.setObfuscatable(false);
|
||||
return declaredName;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
/*package*/ JsName declareObfuscatableName(@NotNull String name) {
|
||||
return scope.declareName(mayBeObfuscateName(name, true));
|
||||
}
|
||||
|
||||
//TODO: temporary solution
|
||||
@NotNull
|
||||
private String mayBeObfuscateName(@NotNull String name, boolean shouldObfuscate) {
|
||||
if (!shouldObfuscate) {
|
||||
return name;
|
||||
}
|
||||
return doObfuscate(name);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String doObfuscate(@NotNull String name) {
|
||||
int obfuscate = 0;
|
||||
String result = name;
|
||||
while (true) {
|
||||
JsName existingNameWithSameIdent = scope.findExistingName(result);
|
||||
boolean isDuplicate = (existingNameWithSameIdent != null) && (scope.ownsName(existingNameWithSameIdent));
|
||||
|
||||
if (!isDuplicate) break;
|
||||
|
||||
result = name + "$" + obfuscate;
|
||||
obfuscate++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public JsName declareTemporary() {
|
||||
return scope.declareTemporary();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsScope jsScope() {
|
||||
return scope;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.context;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsName;
|
||||
import com.google.dart.compiler.backend.js.ast.JsScope;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getFQName;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
* <p/>
|
||||
* Provides a mechanism to bind some of the kotlin/java declations with library implementations.
|
||||
* Makes sense only for those declaration that cannot be annotated. (Use library annotation in this case)
|
||||
*/
|
||||
public final class StandardClasses {
|
||||
|
||||
private final class Builder {
|
||||
|
||||
@Nullable
|
||||
private /*var*/ String currentFQName = null;
|
||||
@Nullable
|
||||
private /*var*/ String currentObjectName = null;
|
||||
|
||||
@NotNull
|
||||
public Builder forFQ(@NotNull String classFQName) {
|
||||
currentFQName = classFQName;
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Builder kotlinClass(@NotNull String kotlinName) {
|
||||
kotlinTopLevelObject(kotlinName);
|
||||
constructor();
|
||||
return this;
|
||||
}
|
||||
|
||||
private void kotlinTopLevelObject(@NotNull String kotlinName) {
|
||||
assert currentFQName != null;
|
||||
currentObjectName = kotlinName;
|
||||
declareKotlinObject(currentFQName, kotlinName);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Builder kotlinFunction(@NotNull String kotlinName) {
|
||||
kotlinTopLevelObject(kotlinName);
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Builder constructor() {
|
||||
assert currentFQName != null;
|
||||
assert currentObjectName != null;
|
||||
declareInner(currentFQName, "<init>", currentObjectName);
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Builder methods(@NotNull String... methodNames) {
|
||||
assert currentFQName != null;
|
||||
declareMethods(currentFQName, methodNames);
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Builder properties(@NotNull String... propertyNames) {
|
||||
assert currentFQName != null;
|
||||
declareReadonlyProperties(currentFQName, propertyNames);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static StandardClasses bindImplementations(@NotNull JsScope kotlinObjectScope) {
|
||||
StandardClasses standardClasses = new StandardClasses(kotlinObjectScope);
|
||||
declareJetObjects(standardClasses);
|
||||
return standardClasses;
|
||||
}
|
||||
|
||||
private static void declareJetObjects(@NotNull StandardClasses standardClasses) {
|
||||
|
||||
standardClasses.declare().forFQ("jet.Iterator").kotlinClass("ArrayIteratorIntrinsic")
|
||||
.methods("next").properties("hasNext");
|
||||
|
||||
standardClasses.declare().forFQ("jet.IntRange").kotlinClass("NumberRange")
|
||||
.methods("iterator", "contains").properties("start", "size", "end", "reversed");
|
||||
|
||||
standardClasses.declare().forFQ("jet.sure").kotlinFunction("sure");
|
||||
|
||||
standardClasses.declare().forFQ("jet.Any.toString").kotlinFunction("toString");
|
||||
|
||||
standardClasses.declare().forFQ("java.util.Collections.<no name provided>.max").kotlinFunction("collectionsMax");
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
private final JsScope kotlinScope;
|
||||
|
||||
|
||||
@NotNull
|
||||
private final Map<String, JsName> standardObjects = new HashMap<String, JsName>();
|
||||
|
||||
@NotNull
|
||||
private final Map<String, JsScope> scopeMap = new HashMap<String, JsScope>();
|
||||
|
||||
private StandardClasses(@NotNull JsScope kotlinScope) {
|
||||
this.kotlinScope = kotlinScope;
|
||||
}
|
||||
|
||||
private void declareTopLevelObjectInScope(@NotNull JsScope scope, @NotNull Map<String, JsName> map,
|
||||
@NotNull String fullQualifiedName, @NotNull String name) {
|
||||
JsName declaredName = scope.declareName(name);
|
||||
declaredName.setObfuscatable(false);
|
||||
map.put(fullQualifiedName, declaredName);
|
||||
scopeMap.put(fullQualifiedName, new JsScope(scope, "scope for " + name));
|
||||
}
|
||||
|
||||
private void declareKotlinObject(@NotNull String fullQualifiedName, @NotNull String kotlinLibName) {
|
||||
declareTopLevelObjectInScope(kotlinScope, standardObjects, fullQualifiedName, kotlinLibName);
|
||||
}
|
||||
|
||||
private void declareInner(@NotNull String fullQualifiedClassName,
|
||||
@NotNull String shortMethodName,
|
||||
@NotNull String javascriptName) {
|
||||
JsScope classScope = scopeMap.get(fullQualifiedClassName);
|
||||
assert classScope != null;
|
||||
String fullQualifiedMethodName = fullQualifiedClassName + "." + shortMethodName;
|
||||
JsName declaredName = classScope.declareName(javascriptName);
|
||||
declaredName.setObfuscatable(false);
|
||||
standardObjects.put(fullQualifiedMethodName, declaredName);
|
||||
}
|
||||
|
||||
private void declareMethods(@NotNull String classFQName,
|
||||
@NotNull String... methodNames) {
|
||||
for (String methodName : methodNames) {
|
||||
declareInner(classFQName, methodName, methodName);
|
||||
}
|
||||
}
|
||||
|
||||
private void declareReadonlyProperties(@NotNull String classFQName,
|
||||
@NotNull String... propertyNames) {
|
||||
for (String propertyName : propertyNames) {
|
||||
declareInner(classFQName, propertyName, propertyName);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isStandardObject(@NotNull DeclarationDescriptor descriptor) {
|
||||
return standardObjects.containsKey(getFQName(descriptor));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsName getStandardObjectName(@NotNull DeclarationDescriptor descriptor) {
|
||||
return standardObjects.get(getFQName(descriptor));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Builder declare() {
|
||||
return new Builder();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,478 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.context;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsName;
|
||||
import com.google.dart.compiler.backend.js.ast.JsNameRef;
|
||||
import com.google.dart.compiler.backend.js.ast.JsProgram;
|
||||
import com.google.dart.compiler.backend.js.ast.JsRootScope;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.types.JetStandardLibrary;
|
||||
import org.jetbrains.k2js.translate.context.generator.Generator;
|
||||
import org.jetbrains.k2js.translate.context.generator.Rule;
|
||||
import org.jetbrains.k2js.translate.intrinsic.Intrinsics;
|
||||
import org.jetbrains.k2js.translate.utils.AnnotationsUtils;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.AnnotationsUtils.*;
|
||||
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.*;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
* <p/>
|
||||
* Aggregates all the static parts of the context.
|
||||
*/
|
||||
public final class StaticContext {
|
||||
|
||||
public static StaticContext generateStaticContext(@NotNull JetStandardLibrary library,
|
||||
@NotNull BindingContext bindingContext) {
|
||||
JsProgram program = new JsProgram("main");
|
||||
JsRootScope jsRootScope = program.getRootScope();
|
||||
Namer namer = Namer.newInstance(jsRootScope);
|
||||
Aliaser aliaser = Aliaser.newInstance();
|
||||
NamingScope scope = NamingScope.rootScope(jsRootScope);
|
||||
Intrinsics intrinsics = Intrinsics.standardLibraryIntrinsics(library);
|
||||
StandardClasses standardClasses =
|
||||
StandardClasses.bindImplementations(namer.getKotlinScope());
|
||||
return new StaticContext(program, bindingContext, aliaser,
|
||||
namer, intrinsics, standardClasses, scope);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final JsProgram program;
|
||||
|
||||
@NotNull
|
||||
private final BindingContext bindingContext;
|
||||
|
||||
@NotNull
|
||||
private final Aliaser aliaser;
|
||||
|
||||
@NotNull
|
||||
private final Namer namer;
|
||||
|
||||
@NotNull
|
||||
private final Intrinsics intrinsics;
|
||||
|
||||
@NotNull
|
||||
private final StandardClasses standardClasses;
|
||||
|
||||
@NotNull
|
||||
private final NamingScope rootScope;
|
||||
|
||||
@NotNull
|
||||
private final Generator<JsName> names = new NameGenerator();
|
||||
@NotNull
|
||||
private final Generator<NamingScope> scopes = new ScopeGenerator();
|
||||
@NotNull
|
||||
private final Generator<JsNameRef> qualifiers = new QualifierGenerator();
|
||||
@NotNull
|
||||
private final Generator<Boolean> qualifierIsNull = new QualifierIsNullGenerator();
|
||||
|
||||
|
||||
//TODO: too many parameters in constructor
|
||||
private StaticContext(@NotNull JsProgram program, @NotNull BindingContext bindingContext,
|
||||
@NotNull Aliaser aliaser,
|
||||
@NotNull Namer namer, @NotNull Intrinsics intrinsics,
|
||||
@NotNull StandardClasses standardClasses, @NotNull NamingScope rootScope) {
|
||||
this.program = program;
|
||||
this.bindingContext = bindingContext;
|
||||
this.aliaser = aliaser;
|
||||
this.namer = namer;
|
||||
this.intrinsics = intrinsics;
|
||||
this.rootScope = rootScope;
|
||||
this.standardClasses = standardClasses;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsProgram getProgram() {
|
||||
return program;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public BindingContext getBindingContext() {
|
||||
return bindingContext;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Aliaser getAliaser() {
|
||||
return aliaser;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Intrinsics getIntrinsics() {
|
||||
return intrinsics;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Namer getNamer() {
|
||||
return namer;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public NamingScope getRootScope() {
|
||||
return rootScope;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public StandardClasses getStandardClasses() {
|
||||
return standardClasses;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public NamingScope getScopeForDescriptor(@NotNull DeclarationDescriptor descriptor) {
|
||||
NamingScope namingScope = scopes.get(descriptor);
|
||||
assert namingScope != null : "Must have a scope for descriptor";
|
||||
return namingScope;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsName getNameForDescriptor(@NotNull DeclarationDescriptor descriptor) {
|
||||
JsName name = names.get(descriptor.getOriginal());
|
||||
assert name != null : "Must have name for descriptor";
|
||||
return name;
|
||||
}
|
||||
|
||||
private final class NameGenerator extends Generator<JsName> {
|
||||
public NameGenerator() {
|
||||
Rule<JsName> namesForStandardClasses = new Rule<JsName>() {
|
||||
@Override
|
||||
@Nullable
|
||||
public JsName apply(@NotNull DeclarationDescriptor data) {
|
||||
if (!standardClasses.isStandardObject(data)) {
|
||||
return null;
|
||||
}
|
||||
return standardClasses.getStandardObjectName(data);
|
||||
}
|
||||
};
|
||||
Rule<JsName> namespacesShouldBeDefinedInRootScope = new Rule<JsName>() {
|
||||
@Override
|
||||
@Nullable
|
||||
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (!(descriptor instanceof NamespaceDescriptor)) {
|
||||
return null;
|
||||
}
|
||||
String nameForNamespace = getNameForNamespace((NamespaceDescriptor) descriptor);
|
||||
return getRootScope().declareUnobfuscatableName(nameForNamespace);
|
||||
}
|
||||
};
|
||||
Rule<JsName> memberDeclarationsInsideParentsScope = new Rule<JsName>() {
|
||||
@Override
|
||||
@Nullable
|
||||
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
NamingScope namingScope = getEnclosingScope(descriptor);
|
||||
return namingScope.declareObfuscatableName(descriptor.getName());
|
||||
}
|
||||
};
|
||||
Rule<JsName> constructorHasTheSameNameAsTheClass = new Rule<JsName>() {
|
||||
@Override
|
||||
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (!(descriptor instanceof ConstructorDescriptor)) {
|
||||
return null;
|
||||
}
|
||||
ClassDescriptor containingClass = getContainingClass(descriptor);
|
||||
assert containingClass != null : "Can't have constructor without a class";
|
||||
return getNameForDescriptor(containingClass);
|
||||
}
|
||||
};
|
||||
Rule<JsName> accessorsHasNamesWithSpecialPrefixes = new Rule<JsName>() {
|
||||
@Override
|
||||
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (!(descriptor instanceof PropertyAccessorDescriptor)) {
|
||||
return null;
|
||||
}
|
||||
boolean isGetter = descriptor instanceof PropertyGetterDescriptor;
|
||||
String propertyName = ((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty().getName();
|
||||
String accessorName = Namer.getNameForAccessor(propertyName, isGetter);
|
||||
NamingScope enclosingScope = getEnclosingScope(descriptor);
|
||||
return enclosingScope.declareObfuscatableName(accessorName);
|
||||
}
|
||||
};
|
||||
|
||||
Rule<JsName> namesAnnotatedAsLibraryHasUnobfuscatableNames = new Rule<JsName>() {
|
||||
@Override
|
||||
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
//TODO: refactor
|
||||
String name = null;
|
||||
AnnotationDescriptor annotation = getAnnotationByName(descriptor, LIBRARY_ANNOTATION_FQNAME);
|
||||
if (annotation != null) {
|
||||
name = AnnotationsUtils.getAnnotationStringParameter(descriptor, LIBRARY_ANNOTATION_FQNAME);
|
||||
name = (!name.isEmpty()) ? name : descriptor.getName();
|
||||
} else {
|
||||
ClassDescriptor containingClass = getContainingClass(descriptor);
|
||||
if (containingClass == null) return null;
|
||||
if (getAnnotationByName(containingClass, LIBRARY_ANNOTATION_FQNAME) != null) {
|
||||
name = descriptor.getName();
|
||||
}
|
||||
}
|
||||
if (name != null) {
|
||||
return getEnclosingScope(descriptor).declareUnobfuscatableName(name);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
Rule<JsName> propertiesCorrespondToSpeciallyTreatedBackingFieldNames = new Rule<JsName>() {
|
||||
@Override
|
||||
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (!(descriptor instanceof PropertyDescriptor)) {
|
||||
return null;
|
||||
}
|
||||
NamingScope enclosingScope = getEnclosingScope(descriptor);
|
||||
return enclosingScope.declareObfuscatableName(Namer.getKotlinBackingFieldName(descriptor.getName()));
|
||||
}
|
||||
};
|
||||
//TODO: hack!
|
||||
Rule<JsName> toStringHack = new Rule<JsName>() {
|
||||
@Override
|
||||
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (!(descriptor instanceof FunctionDescriptor)) {
|
||||
return null;
|
||||
}
|
||||
if (!descriptor.getName().equals("toString")) {
|
||||
return null;
|
||||
}
|
||||
if (((FunctionDescriptor) descriptor).getValueParameters().isEmpty()) {
|
||||
return getEnclosingScope(descriptor).declareUnobfuscatableName("toString");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
};
|
||||
Rule<JsName> namesForNativeObjectsAreUnobfuscatable = new Rule<JsName>() {
|
||||
@Override
|
||||
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
String name = null;
|
||||
AnnotationDescriptor annotation = getAnnotationByName(descriptor, NATIVE_ANNOTATION_FQNAME);
|
||||
if (annotation != null) {
|
||||
name = AnnotationsUtils.getAnnotationStringParameter(descriptor, NATIVE_ANNOTATION_FQNAME);
|
||||
name = (!name.isEmpty()) ? name : descriptor.getName();
|
||||
} else {
|
||||
ClassDescriptor containingClass = getContainingClass(descriptor);
|
||||
if (containingClass == null) return null;
|
||||
if (getAnnotationByName(containingClass, NATIVE_ANNOTATION_FQNAME) != null) {
|
||||
name = descriptor.getName();
|
||||
}
|
||||
}
|
||||
if (name != null) {
|
||||
return getEnclosingScope(descriptor).declareUnobfuscatableName(name);
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
};
|
||||
Rule<JsName> overridingDescriptorsReferToOriginalName = new Rule<JsName>() {
|
||||
@Override
|
||||
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
//TODO: refactor
|
||||
if (descriptor instanceof FunctionDescriptor) {
|
||||
Set<? extends FunctionDescriptor> overriddenDescriptors = ((FunctionDescriptor) descriptor).getOverriddenDescriptors();
|
||||
if (overriddenDescriptors.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
//assert overriddenDescriptors.size() == 1;
|
||||
//TODO: for now translator can't deal with multiple inheritance good enough
|
||||
for (FunctionDescriptor overriddenDescriptor : overriddenDescriptors) {
|
||||
return getNameForDescriptor(overriddenDescriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
addRule(namesForStandardClasses);
|
||||
addRule(constructorHasTheSameNameAsTheClass);
|
||||
addRule(namesAnnotatedAsLibraryHasUnobfuscatableNames);
|
||||
addRule(namesForNativeObjectsAreUnobfuscatable);
|
||||
addRule(toStringHack);
|
||||
addRule(propertiesCorrespondToSpeciallyTreatedBackingFieldNames);
|
||||
addRule(namespacesShouldBeDefinedInRootScope);
|
||||
addRule(accessorsHasNamesWithSpecialPrefixes);
|
||||
addRule(overridingDescriptorsReferToOriginalName);
|
||||
addRule(memberDeclarationsInsideParentsScope);
|
||||
}
|
||||
}
|
||||
|
||||
private NamingScope getEnclosingScope(@NotNull DeclarationDescriptor descriptor) {
|
||||
DeclarationDescriptor containingDeclaration = getContainingDeclaration(descriptor);
|
||||
return getScopeForDescriptor(containingDeclaration.getOriginal());
|
||||
}
|
||||
|
||||
|
||||
private final class ScopeGenerator extends Generator<NamingScope> {
|
||||
|
||||
public ScopeGenerator() {
|
||||
Rule<NamingScope> generateNewScopesForClassesWithNoAncestors = new Rule<NamingScope>() {
|
||||
@Override
|
||||
public NamingScope apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (!(descriptor instanceof ClassDescriptor)) {
|
||||
return null;
|
||||
}
|
||||
if (getSuperclass((ClassDescriptor) descriptor) == null) {
|
||||
return getRootScope().innerScope("Scope for class " + descriptor.getName());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
Rule<NamingScope> generateInnerScopesForDerivedClasses = new Rule<NamingScope>() {
|
||||
@Override
|
||||
public NamingScope apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (!(descriptor instanceof ClassDescriptor)) {
|
||||
return null;
|
||||
}
|
||||
ClassDescriptor superclass = getSuperclass((ClassDescriptor) descriptor);
|
||||
if (superclass == null) {
|
||||
return null;
|
||||
}
|
||||
return getScopeForDescriptor(superclass).innerScope("Scope for class " + descriptor.getName());
|
||||
}
|
||||
};
|
||||
Rule<NamingScope> generateNewScopesForNamespaceDescriptors = new Rule<NamingScope>() {
|
||||
@Override
|
||||
public NamingScope apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (!(descriptor instanceof NamespaceDescriptor)) {
|
||||
return null;
|
||||
}
|
||||
return getRootScope().innerScope("Namespace " + descriptor.getName());
|
||||
}
|
||||
};
|
||||
Rule<NamingScope> generateInnerScopesForMembers = new Rule<NamingScope>() {
|
||||
@Override
|
||||
public NamingScope apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
NamingScope enclosingScope = getEnclosingScope(descriptor);
|
||||
return enclosingScope.innerScope("Scope for member " + descriptor.getName());
|
||||
}
|
||||
};
|
||||
addRule(generateNewScopesForClassesWithNoAncestors);
|
||||
addRule(generateInnerScopesForDerivedClasses);
|
||||
addRule(generateNewScopesForNamespaceDescriptors);
|
||||
addRule(generateInnerScopesForMembers);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public JsNameRef getQualifierForDescriptor(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (qualifierIsNull.get(descriptor) != null) {
|
||||
return null;
|
||||
}
|
||||
return qualifiers.get(descriptor.getOriginal());
|
||||
}
|
||||
|
||||
private final class QualifierGenerator extends Generator<JsNameRef> {
|
||||
public QualifierGenerator() {
|
||||
Rule<JsNameRef> namespacesHaveNoQualifiers = new Rule<JsNameRef>() {
|
||||
@Override
|
||||
public JsNameRef apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (!standardClasses.isStandardObject(descriptor)) {
|
||||
return null;
|
||||
}
|
||||
return namer.kotlinObject();
|
||||
}
|
||||
};
|
||||
Rule<JsNameRef> namespaceLevelDeclarationsHaveEnclosingNamespacesNamesAsQualifier = new Rule<JsNameRef>() {
|
||||
@Override
|
||||
public JsNameRef apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
DeclarationDescriptor containingDeclaration = getContainingDeclaration(descriptor);
|
||||
if (!(containingDeclaration instanceof NamespaceDescriptor)) {
|
||||
return null;
|
||||
}
|
||||
JsName containingDeclarationName = getNameForDescriptor(containingDeclaration);
|
||||
return containingDeclarationName.makeRef();
|
||||
}
|
||||
};
|
||||
Rule<JsNameRef> constructorHaveTheSameQualifierAsTheClass = new Rule<JsNameRef>() {
|
||||
@Override
|
||||
public JsNameRef apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (!(descriptor instanceof ConstructorDescriptor)) {
|
||||
return null;
|
||||
}
|
||||
ClassDescriptor containingClass = getContainingClass(descriptor);
|
||||
assert containingClass != null : "Can't have constructor without a class";
|
||||
return getQualifierForDescriptor(containingClass);
|
||||
}
|
||||
};
|
||||
Rule<JsNameRef> libraryObjectsHaveKotlinQualifier = new Rule<JsNameRef>() {
|
||||
|
||||
@Override
|
||||
public JsNameRef apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (getAnnotationByName(descriptor, AnnotationsUtils.LIBRARY_ANNOTATION_FQNAME) != null) {
|
||||
return namer.kotlinObject();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
Rule<JsNameRef> membersOfAnnotatedClassesHaveKotlinQualifier = new Rule<JsNameRef>() {
|
||||
@Override
|
||||
public JsNameRef apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
ClassDescriptor containingClass = getContainingClass(descriptor);
|
||||
if (containingClass == null) {
|
||||
return null;
|
||||
}
|
||||
if (getAnnotationByName(descriptor, LIBRARY_ANNOTATION_FQNAME) != null) {
|
||||
return namer.kotlinObject();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
addRule(libraryObjectsHaveKotlinQualifier);
|
||||
addRule(membersOfAnnotatedClassesHaveKotlinQualifier);
|
||||
addRule(constructorHaveTheSameQualifierAsTheClass);
|
||||
addRule(namespacesHaveNoQualifiers);
|
||||
addRule(namespaceLevelDeclarationsHaveEnclosingNamespacesNamesAsQualifier);
|
||||
}
|
||||
}
|
||||
|
||||
private class QualifierIsNullGenerator extends Generator<Boolean> {
|
||||
|
||||
private QualifierIsNullGenerator() {
|
||||
Rule<Boolean> propertiesHaveNoQualifiers = new Rule<Boolean>() {
|
||||
@Override
|
||||
public Boolean apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (!(descriptor instanceof PropertyDescriptor)) {
|
||||
return null;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
Rule<Boolean> variableAsFunctionsHaveNoQualifiers = new Rule<Boolean>() {
|
||||
@Override
|
||||
public Boolean apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (!isVariableAsFunction(descriptor)) {
|
||||
return null;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
//TODO: hack!
|
||||
Rule<Boolean> nativeObjectsHaveNoQualifiers = new Rule<Boolean>() {
|
||||
@Override
|
||||
public Boolean apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (!AnnotationsUtils.isNativeObject(descriptor)) {
|
||||
return null;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
addRule(propertiesHaveNoQualifiers);
|
||||
addRule(variableAsFunctionsHaveNoQualifiers);
|
||||
addRule(nativeObjectsHaveNoQualifiers);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.context;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.backend.js.ast.JsName;
|
||||
import com.google.dart.compiler.backend.js.ast.JsNameRef;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class TemporaryVariable {
|
||||
|
||||
@NotNull
|
||||
private final JsExpression assignmentExpression;
|
||||
@NotNull
|
||||
private final JsName variableName;
|
||||
|
||||
/*package*/ TemporaryVariable(@NotNull JsName temporaryName, @NotNull JsExpression initExpression) {
|
||||
this.variableName = temporaryName;
|
||||
this.assignmentExpression = AstUtil.newAssignment(variableName.makeRef(), initExpression);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsNameRef reference() {
|
||||
return variableName.makeRef();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsName name() {
|
||||
return variableName;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsExpression assignmentExpression() {
|
||||
return assignmentExpression;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.context;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.dart.compiler.backend.js.ast.*;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.k2js.translate.intrinsic.Intrinsics;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForElement;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
* <p/>
|
||||
* All the info about the state of the translation process.
|
||||
*/
|
||||
public final class TranslationContext {
|
||||
|
||||
@NotNull
|
||||
private final DynamicContext dynamicContext;
|
||||
@NotNull
|
||||
private final StaticContext staticContext;
|
||||
@NotNull
|
||||
private final Map<JsScope, JsFunction> scopeToFunction = Maps.newHashMap();
|
||||
|
||||
@NotNull
|
||||
public static TranslationContext rootContext(@NotNull StaticContext staticContext) {
|
||||
JsProgram program = staticContext.getProgram();
|
||||
JsBlock globalBlock = program.getGlobalBlock();
|
||||
return new TranslationContext(staticContext,
|
||||
DynamicContext.rootContext(staticContext.getRootScope(), globalBlock));
|
||||
}
|
||||
|
||||
private TranslationContext(@NotNull StaticContext staticContext, @NotNull DynamicContext dynamicContext) {
|
||||
this.dynamicContext = dynamicContext;
|
||||
this.staticContext = staticContext;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public TranslationContext contextWithScope(@NotNull NamingScope newScope) {
|
||||
return new TranslationContext(staticContext, DynamicContext.contextWithScope(newScope));
|
||||
}
|
||||
|
||||
// Note: Should be used ONLY if scope has no corresponding descriptor
|
||||
@NotNull
|
||||
public TranslationContext innerJsScope(@NotNull JsScope enclosingScope) {
|
||||
return new TranslationContext(staticContext, dynamicContext.innerScope(enclosingScope));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public TranslationContext innerBlock(@NotNull JsBlock block) {
|
||||
return new TranslationContext(staticContext, dynamicContext.innerBlock(block));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public TranslationContext newDeclaration(@NotNull DeclarationDescriptor descriptor) {
|
||||
return contextWithScope(getScopeForDescriptor(descriptor));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public TranslationContext newDeclaration(@NotNull PsiElement element) {
|
||||
return newDeclaration(getDescriptorForElement(bindingContext(), element));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public BindingContext bindingContext() {
|
||||
return staticContext.getBindingContext();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public NamingScope getScopeForDescriptor(@NotNull DeclarationDescriptor descriptor) {
|
||||
return staticContext.getScopeForDescriptor(descriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public NamingScope getScopeForElement(@NotNull PsiElement element) {
|
||||
DeclarationDescriptor descriptorForElement = getDescriptorForElement(bindingContext(), element);
|
||||
return getScopeForDescriptor(descriptorForElement);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsName getNameForElement(@NotNull PsiElement element) {
|
||||
DeclarationDescriptor descriptor = getDescriptorForElement(bindingContext(), element);
|
||||
return getNameForDescriptor(descriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsName getNameForDescriptor(@NotNull DeclarationDescriptor descriptor) {
|
||||
return staticContext.getNameForDescriptor(descriptor);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public JsNameRef getQualifierForDescriptor(@NotNull DeclarationDescriptor descriptor) {
|
||||
return staticContext.getQualifierForDescriptor(descriptor.getOriginal());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public TemporaryVariable declareTemporary(@NotNull JsExpression initExpression) {
|
||||
return dynamicContext.declareTemporary(initExpression);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Aliaser aliaser() {
|
||||
return staticContext.getAliaser();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Namer namer() {
|
||||
return staticContext.getNamer();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Intrinsics intrinsics() {
|
||||
return staticContext.getIntrinsics();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsProgram program() {
|
||||
return staticContext.getProgram();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private StandardClasses standardClasses() {
|
||||
return staticContext.getStandardClasses();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public NamingScope getScope() {
|
||||
return dynamicContext.getScope();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsScope jsScope() {
|
||||
return dynamicContext.jsScope();
|
||||
}
|
||||
|
||||
public void addStatementToCurrentBlock(@NotNull JsStatement statement) {
|
||||
dynamicContext.jsBlock().getStatements().add(statement);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.context.generator;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public class Generator<V> {
|
||||
|
||||
|
||||
@NotNull
|
||||
private final Map<DeclarationDescriptor, V> values = Maps.newHashMap();
|
||||
@NotNull
|
||||
private final List<Rule<V>> rules = Lists.newArrayList();
|
||||
|
||||
public void addRule(@NotNull Rule<V> rule) {
|
||||
rules.add(rule);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public V get(@NotNull DeclarationDescriptor descriptor) {
|
||||
V result = values.get(descriptor);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
result = generate(descriptor);
|
||||
values.put(descriptor, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private V generate(@NotNull DeclarationDescriptor descriptor) {
|
||||
V result = null;
|
||||
for (Rule<V> rule : rules) {
|
||||
result = rule.apply(descriptor);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.context.generator;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public interface Rule<V> {
|
||||
|
||||
@Nullable
|
||||
V apply(@NotNull DeclarationDescriptor descriptor);
|
||||
}
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.declaration;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.*;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetClass;
|
||||
import org.jetbrains.k2js.translate.context.Namer;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
import org.jetbrains.k2js.translate.general.Translation;
|
||||
import org.jetbrains.k2js.translate.utils.BindingUtils;
|
||||
import org.jetbrains.k2js.translate.utils.ClassSorter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.getAllClassesDefinedInNamespace;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
* <p/>
|
||||
* Generates a big block where are all the classes(objects representing them) are created.
|
||||
*/
|
||||
public final class ClassDeclarationTranslator extends AbstractTranslator {
|
||||
|
||||
@NotNull
|
||||
private final List<ClassDescriptor> descriptors;
|
||||
@NotNull
|
||||
private final Map<JsName, JsName> localToGlobalClassName;
|
||||
@NotNull
|
||||
private final JsScope dummyFunctionScope;
|
||||
@Nullable
|
||||
private JsName declarationsObject = null;
|
||||
@Nullable
|
||||
private JsStatement declarationsStatement = null;
|
||||
|
||||
public ClassDeclarationTranslator(@NotNull List<ClassDescriptor> descriptors,
|
||||
@NotNull TranslationContext context) {
|
||||
super(context);
|
||||
this.descriptors = descriptors;
|
||||
this.localToGlobalClassName = new HashMap<JsName, JsName>();
|
||||
this.dummyFunctionScope = new JsScope(context().jsScope(), "class declaration function");
|
||||
}
|
||||
|
||||
public void generateDeclarations() {
|
||||
declarationsObject = context().jsScope().declareName(Namer.nameForClassesVariable());
|
||||
assert declarationsObject != null;
|
||||
declarationsStatement =
|
||||
AstUtil.newVar(declarationsObject, generateDummyFunctionInvocation());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsName getDeclarationsObjectName() {
|
||||
assert declarationsObject != null : "Should run generateDeclarations first";
|
||||
return declarationsObject;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsStatement getDeclarationsStatement() {
|
||||
assert declarationsStatement != null : "Should run generateDeclarations first";
|
||||
return declarationsStatement;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsInvocation generateDummyFunctionInvocation() {
|
||||
JsFunction dummyFunction = JsFunction.getAnonymousFunctionWithScope(dummyFunctionScope);
|
||||
List<JsStatement> classDeclarations = generateClassDeclarationStatements();
|
||||
classDeclarations.add(new JsReturn(generateReturnedObjectLiteral()));
|
||||
dummyFunction.setBody(AstUtil.newBlock(classDeclarations));
|
||||
return AstUtil.newInvocation(dummyFunction);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsObjectLiteral generateReturnedObjectLiteral() {
|
||||
JsObjectLiteral returnedValueLiteral = new JsObjectLiteral();
|
||||
for (JsName localName : localToGlobalClassName.keySet()) {
|
||||
returnedValueLiteral.getPropertyInitializers().add(classEntry(localName));
|
||||
}
|
||||
return returnedValueLiteral;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsPropertyInitializer classEntry(@NotNull JsName localName) {
|
||||
return new JsPropertyInitializer(localToGlobalClassName.get(localName).makeRef(), localName.makeRef());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<JsStatement> generateClassDeclarationStatements() {
|
||||
List<JsStatement> classDeclarations = new ArrayList<JsStatement>();
|
||||
for (JetClass jetClass : getClassDeclarations()) {
|
||||
classDeclarations.add(generateDeclaration(jetClass));
|
||||
}
|
||||
removeAliases();
|
||||
return classDeclarations;
|
||||
}
|
||||
|
||||
private void removeAliases() {
|
||||
for (JetClass jetClass : getClassDeclarations()) {
|
||||
ClassDescriptor descriptor = BindingUtils.getClassDescriptor(bindingContext(), jetClass);
|
||||
aliaser().removeAliasForDescriptor(descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<JetClass> getClassDeclarations() {
|
||||
List<JetClass> classes = new ArrayList<JetClass>();
|
||||
for (ClassDescriptor classDescriptor : descriptors) {
|
||||
classes.add(BindingUtils.getClassForDescriptor(bindingContext(), classDescriptor));
|
||||
}
|
||||
return ClassSorter.sortUsingInheritanceOrder(classes, bindingContext());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsStatement generateDeclaration(@NotNull JetClass declaration) {
|
||||
JsName localClassName = generateLocalAlias(declaration);
|
||||
JsInvocation classDeclarationExpression =
|
||||
Translation.translateClassDeclaration(declaration, context());
|
||||
return AstUtil.newVar(localClassName, classDeclarationExpression);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsName generateLocalAlias(@NotNull JetClass declaration) {
|
||||
JsName globalClassName = context().getNameForElement(declaration);
|
||||
JsName localAlias = dummyFunctionScope.declareTemporary();
|
||||
localToGlobalClassName.put(localAlias, globalClassName);
|
||||
ClassDescriptor descriptor = BindingUtils.getClassDescriptor(bindingContext(), declaration);
|
||||
aliaser().setAliasForDescriptor(descriptor, localAlias);
|
||||
return localAlias;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsObjectLiteral classDeclarationsForNamespace(@NotNull NamespaceDescriptor namespaceDescriptor) {
|
||||
JsObjectLiteral result = new JsObjectLiteral();
|
||||
for (ClassDescriptor classDescriptor : getAllClassesDefinedInNamespace(namespaceDescriptor)) {
|
||||
result.getPropertyInitializers().add(getClassNameToClassObject(classDescriptor));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsPropertyInitializer getClassNameToClassObject(@NotNull ClassDescriptor classDescriptor) {
|
||||
JsName className = context().getNameForDescriptor(classDescriptor);
|
||||
JsNameRef alreadyDefinedClassReferernce = AstUtil.qualified(className, getDeclarationsObjectName().makeRef());
|
||||
return new JsPropertyInitializer(className.makeRef(), alreadyDefinedClassReferernce);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.declaration;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.*;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassKind;
|
||||
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetClassOrObject;
|
||||
import org.jetbrains.jet.lang.psi.JetParameter;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
import org.jetbrains.k2js.translate.general.Translation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getClassDescriptor;
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getPropertyDescriptorForConstructorParameter;
|
||||
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.findAncestorClass;
|
||||
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.getSuperclassDescriptors;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getPrimaryConstructorParameters;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
* <p/>
|
||||
* Generates a definition of a single class.
|
||||
*/
|
||||
public final class ClassTranslator extends AbstractTranslator {
|
||||
|
||||
@NotNull
|
||||
public static JsPropertyInitializer translateAsProperty(@NotNull JetClassOrObject classDeclaration,
|
||||
@NotNull TranslationContext context) {
|
||||
JsInvocation classCreationExpression = generateClassCreationExpression(classDeclaration, context);
|
||||
JsName className = context.getNameForElement(classDeclaration);
|
||||
return new JsPropertyInitializer(className.makeRef(), classCreationExpression);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsInvocation generateClassCreationExpression(@NotNull JetClassOrObject classDeclaration,
|
||||
@NotNull TranslationContext context) {
|
||||
return (new ClassTranslator(classDeclaration, context)).translateClass();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final DeclarationBodyVisitor declarationBodyVisitor = new DeclarationBodyVisitor();
|
||||
|
||||
@NotNull
|
||||
private final JetClassOrObject classDeclaration;
|
||||
|
||||
@NotNull
|
||||
private final ClassDescriptor descriptor;
|
||||
|
||||
private ClassTranslator(@NotNull JetClassOrObject classDeclaration, @NotNull TranslationContext context) {
|
||||
super(context.newDeclaration(classDeclaration));
|
||||
this.descriptor = getClassDescriptor(context.bindingContext(), classDeclaration);
|
||||
this.classDeclaration = classDeclaration;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsInvocation translateClass() {
|
||||
JsInvocation jsClassDeclaration = classCreateMethodInvocation();
|
||||
addSuperclassReferences(jsClassDeclaration);
|
||||
addClassOwnDeclarations(jsClassDeclaration);
|
||||
return jsClassDeclaration;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsInvocation classCreateMethodInvocation() {
|
||||
if (isObject()) {
|
||||
return AstUtil.newInvocation(context().namer().objectCreationMethodReference());
|
||||
} else if (isTrait()) {
|
||||
return AstUtil.newInvocation(context().namer().traitCreationMethodReference());
|
||||
} else {
|
||||
return AstUtil.newInvocation(context().namer().classCreationMethodReference());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isObject() {
|
||||
return descriptor.getKind().equals(ClassKind.OBJECT);
|
||||
}
|
||||
|
||||
private boolean isTrait() {
|
||||
return descriptor.getKind().equals(ClassKind.TRAIT);
|
||||
}
|
||||
|
||||
private void addClassOwnDeclarations(@NotNull JsInvocation jsClassDeclaration) {
|
||||
JsObjectLiteral jsClassDescription = translateClassDeclarations();
|
||||
jsClassDeclaration.getArguments().add(jsClassDescription);
|
||||
}
|
||||
|
||||
private void addSuperclassReferences(@NotNull JsInvocation jsClassDeclaration) {
|
||||
for (JsExpression superClassReference : getSuperclassNameReferences()) {
|
||||
jsClassDeclaration.getArguments().add(superClassReference);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<JsExpression> getSuperclassNameReferences() {
|
||||
List<JsExpression> superclassReferences = new ArrayList<JsExpression>();
|
||||
List<ClassDescriptor> superclassDescriptors = getSuperclassDescriptors(descriptor);
|
||||
addAncestorClass(superclassReferences, superclassDescriptors);
|
||||
addTraits(superclassReferences, superclassDescriptors);
|
||||
return superclassReferences;
|
||||
}
|
||||
|
||||
private void addTraits(@NotNull List<JsExpression> superclassReferences,
|
||||
@NotNull List<ClassDescriptor> superclassDescriptors) {
|
||||
for (ClassDescriptor superClassDescriptor :
|
||||
superclassDescriptors) {
|
||||
assert (superClassDescriptor.getKind() == ClassKind.TRAIT) : "Only traits are expected here";
|
||||
superclassReferences.add(getClassReference(superClassDescriptor));
|
||||
}
|
||||
}
|
||||
|
||||
private void addAncestorClass(@NotNull List<JsExpression> superclassReferences,
|
||||
@NotNull List<ClassDescriptor> superclassDescriptors) {
|
||||
//here we remove ancestor class from the list
|
||||
ClassDescriptor ancestorClass = findAndRemoveAncestorClass(superclassDescriptors);
|
||||
if (ancestorClass != null) {
|
||||
superclassReferences.add(getClassReference(ancestorClass));
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression getClassReference(@NotNull ClassDescriptor superClassDescriptor) {
|
||||
//NOTE: aliasing here is needed for the declaration generation step
|
||||
if (aliaser().hasAliasForDeclaration(superClassDescriptor)) {
|
||||
return aliaser().getAliasForDeclaration(superClassDescriptor).makeRef();
|
||||
}
|
||||
return context().getNameForDescriptor(superClassDescriptor).makeRef();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ClassDescriptor findAndRemoveAncestorClass(@NotNull List<ClassDescriptor> superclassDescriptors) {
|
||||
ClassDescriptor ancestorClass = findAncestorClass(superclassDescriptors);
|
||||
superclassDescriptors.remove(ancestorClass);
|
||||
return ancestorClass;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsObjectLiteral translateClassDeclarations() {
|
||||
List<JsPropertyInitializer> propertyList = new ArrayList<JsPropertyInitializer>();
|
||||
if (!isTrait()) {
|
||||
propertyList.add(Translation.generateClassInitializerMethod(classDeclaration, context()));
|
||||
}
|
||||
propertyList.addAll(translatePropertiesAsConstructorParameters());
|
||||
propertyList.addAll(declarationBodyVisitor.traverseClass(classDeclaration, context()));
|
||||
return new JsObjectLiteral(propertyList);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<JsPropertyInitializer> translatePropertiesAsConstructorParameters() {
|
||||
List<JsPropertyInitializer> result = new ArrayList<JsPropertyInitializer>();
|
||||
for (JetParameter parameter : getPrimaryConstructorParameters(classDeclaration)) {
|
||||
PropertyDescriptor descriptor =
|
||||
getPropertyDescriptorForConstructorParameter(bindingContext(), parameter);
|
||||
if (descriptor != null) {
|
||||
result.addAll(PropertyTranslator.translateAccessors(descriptor, context()));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.declaration;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsPropertyInitializer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.Translation;
|
||||
import org.jetbrains.k2js.translate.general.TranslatorVisitor;
|
||||
import org.jetbrains.k2js.translate.utils.BindingUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getDeclarationsForNamespace;
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getPropertyDescriptorForObjectDeclaration;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class DeclarationBodyVisitor extends TranslatorVisitor<List<JsPropertyInitializer>> {
|
||||
|
||||
|
||||
@NotNull
|
||||
public List<JsPropertyInitializer> traverseClass(@NotNull JetClassOrObject jetClass,
|
||||
@NotNull TranslationContext context) {
|
||||
List<JsPropertyInitializer> properties = new ArrayList<JsPropertyInitializer>();
|
||||
for (JetDeclaration declaration : jetClass.getDeclarations()) {
|
||||
properties.addAll(declaration.accept(this, context));
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<JsPropertyInitializer> traverseNamespace(@NotNull NamespaceDescriptor namespace,
|
||||
@NotNull TranslationContext context) {
|
||||
List<JsPropertyInitializer> properties = new ArrayList<JsPropertyInitializer>();
|
||||
for (JetDeclaration declaration : getDeclarationsForNamespace(context.bindingContext(), namespace)) {
|
||||
properties.addAll(declaration.accept(this, context));
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<JsPropertyInitializer> visitClass(@NotNull JetClass expression, @NotNull TranslationContext context) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<JsPropertyInitializer> visitNamedFunction(@NotNull JetNamedFunction expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return Collections.singletonList(Translation.functionTranslator(expression, context).translateAsMethod());
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<JsPropertyInitializer> visitProperty(@NotNull JetProperty expression,
|
||||
@NotNull TranslationContext context) {
|
||||
PropertyDescriptor propertyDescriptor =
|
||||
BindingUtils.getPropertyDescriptor(context.bindingContext(), expression);
|
||||
return PropertyTranslator.translateAccessors(propertyDescriptor, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<JsPropertyInitializer> visitObjectDeclaration(@NotNull JetObjectDeclaration expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return Collections.singletonList(ClassTranslator.translateAsProperty(expression, context));
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<JsPropertyInitializer> visitObjectDeclarationName(@NotNull JetObjectDeclarationName expression,
|
||||
@NotNull TranslationContext context) {
|
||||
PropertyDescriptor propertyDescriptor =
|
||||
getPropertyDescriptorForObjectDeclaration(context.bindingContext(), expression);
|
||||
return PropertyTranslator.translateAccessors(propertyDescriptor, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<JsPropertyInitializer> visitAnonymousInitializer(@NotNull JetClassInitializer expression,
|
||||
@NotNull TranslationContext context) {
|
||||
// parsed it in initializer visitor => no additional actions are needed
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.declaration;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.dart.compiler.backend.js.ast.JsStatement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getAllNonNativeNamespaceDescriptors;
|
||||
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.getAllClassesDefinedInNamespace;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class NamespaceDeclarationTranslator extends AbstractTranslator {
|
||||
|
||||
public static List<JsStatement> translateFiles(@NotNull List<JetFile> files, @NotNull TranslationContext context) {
|
||||
Set<NamespaceDescriptor> namespaceDescriptorSet = getAllNonNativeNamespaceDescriptors(context.bindingContext(), files);
|
||||
return (new NamespaceDeclarationTranslator(Lists.newArrayList(namespaceDescriptorSet), context)).translate();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final ClassDeclarationTranslator classDeclarationTranslator;
|
||||
@NotNull
|
||||
private final List<NamespaceDescriptor> namespaceDescriptors;
|
||||
|
||||
private NamespaceDeclarationTranslator(@NotNull List<NamespaceDescriptor> namespaceDescriptors,
|
||||
@NotNull TranslationContext context) {
|
||||
super(context);
|
||||
this.namespaceDescriptors = namespaceDescriptors;
|
||||
this.classDeclarationTranslator = new ClassDeclarationTranslator(getAllClasses(), context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<ClassDescriptor> getAllClasses() {
|
||||
List<ClassDescriptor> result = Lists.newArrayList();
|
||||
for (NamespaceDescriptor namespaceDescriptor : namespaceDescriptors) {
|
||||
result.addAll(getAllClassesDefinedInNamespace(namespaceDescriptor));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<JsStatement> translate() {
|
||||
List<JsStatement> result = classesDeclarations();
|
||||
result.addAll(namespacesDeclarations());
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<JsStatement> classesDeclarations() {
|
||||
List<JsStatement> result = Lists.newArrayList();
|
||||
classDeclarationTranslator.generateDeclarations();
|
||||
result.add(classDeclarationTranslator.getDeclarationsStatement());
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<JsStatement> namespacesDeclarations() {
|
||||
List<JsStatement> result = Lists.newArrayList();
|
||||
List<NamespaceTranslator> namespaceTranslators = getTranslatorsForNonEmptyNamespaces();
|
||||
result.addAll(declarationStatements(namespaceTranslators));
|
||||
result.addAll(initializeStatements(namespaceTranslators));
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<NamespaceTranslator> getTranslatorsForNonEmptyNamespaces() {
|
||||
List<NamespaceTranslator> namespaceTranslators = Lists.newArrayList();
|
||||
for (NamespaceDescriptor descriptor : namespaceDescriptors) {
|
||||
NamespaceTranslator namespaceTranslator =
|
||||
new NamespaceTranslator(descriptor, classDeclarationTranslator, context());
|
||||
if (!namespaceTranslator.isNamespaceEmpty()) {
|
||||
namespaceTranslators.add(namespaceTranslator);
|
||||
}
|
||||
}
|
||||
return namespaceTranslators;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<JsStatement> declarationStatements(@NotNull List<NamespaceTranslator> namespaceTranslators) {
|
||||
List<JsStatement> result = Lists.newArrayList();
|
||||
for (NamespaceTranslator translator : namespaceTranslators) {
|
||||
result.add(translator.getDeclarationStatement());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<JsStatement> initializeStatements(@NotNull List<NamespaceTranslator> namespaceTranslators) {
|
||||
List<JsStatement> result = Lists.newArrayList();
|
||||
for (NamespaceTranslator translator : namespaceTranslators) {
|
||||
result.add(translator.getInitializeStatement());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.declaration;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.*;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
|
||||
import org.jetbrains.k2js.translate.context.Namer;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
import org.jetbrains.k2js.translate.general.Translation;
|
||||
import org.jetbrains.k2js.translate.utils.BindingUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Pavel.Talanov
|
||||
* <p/>
|
||||
* Genereate code for a single descriptor.
|
||||
*/
|
||||
public final class NamespaceTranslator extends AbstractTranslator {
|
||||
|
||||
@NotNull
|
||||
private final NamespaceDescriptor descriptor;
|
||||
@NotNull
|
||||
private final JsName namespaceName;
|
||||
@NotNull
|
||||
private final ClassDeclarationTranslator classDeclarationTranslator;
|
||||
|
||||
/*package*/ NamespaceTranslator(@NotNull NamespaceDescriptor descriptor,
|
||||
@NotNull ClassDeclarationTranslator classDeclarationTranslator,
|
||||
@NotNull TranslationContext context) {
|
||||
super(context.newDeclaration(descriptor));
|
||||
this.descriptor = descriptor;
|
||||
this.namespaceName = context.getNameForDescriptor(descriptor);
|
||||
this.classDeclarationTranslator = classDeclarationTranslator;
|
||||
}
|
||||
|
||||
//TODO: at the moment this check is very ineffective, possible solution is to cash the result of getDFN
|
||||
// other solution is to determine it's not affecting performance :D
|
||||
public boolean isNamespaceEmpty() {
|
||||
return BindingUtils.getDeclarationsForNamespace(bindingContext(), descriptor).isEmpty();
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
public JsStatement getInitializeStatement() {
|
||||
JsNameRef initializeMethodReference = Namer.initializeMethodReference();
|
||||
AstUtil.setQualifier(initializeMethodReference, namespaceName.makeRef());
|
||||
return AstUtil.newInvocation(initializeMethodReference).makeStmt();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsInvocation namespaceCreateMethodInvocation() {
|
||||
return AstUtil.newInvocation(context().namer().namespaceCreationMethodReference());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsStatement getDeclarationStatement() {
|
||||
JsInvocation namespaceDeclaration = namespaceCreateMethodInvocation();
|
||||
addMemberDeclarations(namespaceDeclaration);
|
||||
addClassesDeclarations(namespaceDeclaration);
|
||||
return AstUtil.newVar(namespaceName, namespaceDeclaration);
|
||||
}
|
||||
|
||||
private void addClassesDeclarations(@NotNull JsInvocation namespaceDeclaration) {
|
||||
namespaceDeclaration.getArguments().add(classDeclarationTranslator.classDeclarationsForNamespace(descriptor));
|
||||
}
|
||||
|
||||
private void addMemberDeclarations(@NotNull JsInvocation jsNamespace) {
|
||||
JsObjectLiteral jsClassDescription = translateNamespaceMemberDeclarations();
|
||||
jsNamespace.getArguments().add(jsClassDescription);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsObjectLiteral translateNamespaceMemberDeclarations() {
|
||||
List<JsPropertyInitializer> propertyList = new ArrayList<JsPropertyInitializer>();
|
||||
propertyList.add(Translation.generateNamespaceInitializerMethod(descriptor, context()));
|
||||
propertyList.addAll(new DeclarationBodyVisitor().traverseNamespace(descriptor, context()));
|
||||
return new JsObjectLiteral(propertyList);
|
||||
}
|
||||
}
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.declaration;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.*;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.PropertyGetterDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.PropertySetterDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetProperty;
|
||||
import org.jetbrains.jet.lang.psi.JetPropertyAccessor;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
import org.jetbrains.k2js.translate.general.Translation;
|
||||
import org.jetbrains.k2js.translate.utils.BindingUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.*;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
* <p/>
|
||||
* Translates single property /w accessors.
|
||||
*/
|
||||
public final class PropertyTranslator extends AbstractTranslator {
|
||||
|
||||
@NotNull
|
||||
private final PropertyDescriptor property;
|
||||
@NotNull
|
||||
private final List<JsPropertyInitializer> accessors = new ArrayList<JsPropertyInitializer>();
|
||||
@Nullable
|
||||
private final JetProperty declaration;
|
||||
|
||||
static public List<JsPropertyInitializer> translateAccessors(@NotNull PropertyDescriptor descriptor,
|
||||
@NotNull TranslationContext context) {
|
||||
PropertyTranslator propertyTranslator = new PropertyTranslator(descriptor, context);
|
||||
return propertyTranslator.translate();
|
||||
}
|
||||
|
||||
private PropertyTranslator(@NotNull PropertyDescriptor property, @NotNull TranslationContext context) {
|
||||
super(context);
|
||||
this.property = property;
|
||||
this.declaration = BindingUtils.getPropertyForDescriptor(bindingContext(), property);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<JsPropertyInitializer> translate() {
|
||||
addGetter();
|
||||
if (property.isVar()) {
|
||||
addSetter();
|
||||
}
|
||||
return accessors;
|
||||
}
|
||||
|
||||
private void addGetter() {
|
||||
if (hasCustomGetter()) {
|
||||
accessors.add(translateCustomAccessor(getCustomGetterDeclaration()));
|
||||
} else {
|
||||
accessors.add(generateDefaultGetter());
|
||||
}
|
||||
}
|
||||
|
||||
private void addSetter() {
|
||||
if (hasCustomSetter()) {
|
||||
accessors.add(translateCustomAccessor(getCustomSetterDeclaration()));
|
||||
} else {
|
||||
accessors.add(generateDefaultSetter());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasCustomGetter() {
|
||||
return ((declaration != null) && (declaration.getGetter() != null));
|
||||
}
|
||||
|
||||
private boolean hasCustomSetter() {
|
||||
return ((declaration != null) && (declaration.getSetter() != null));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JetPropertyAccessor getCustomGetterDeclaration() {
|
||||
assert declaration != null;
|
||||
JetPropertyAccessor getterDeclaration = declaration.getGetter();
|
||||
assert getterDeclaration != null;
|
||||
return getterDeclaration;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JetPropertyAccessor getCustomSetterDeclaration() {
|
||||
assert declaration != null;
|
||||
JetPropertyAccessor setter = declaration.getSetter();
|
||||
assert setter != null;
|
||||
return setter;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsPropertyInitializer generateDefaultGetter() {
|
||||
PropertyGetterDescriptor getterDescriptor = property.getGetter();
|
||||
assert getterDescriptor != null : "Getter descriptor should not be null";
|
||||
return AstUtil.newNamedMethod(context().getNameForDescriptor(getterDescriptor),
|
||||
generateDefaultGetterFunction(getterDescriptor));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsFunction generateDefaultGetterFunction(@NotNull PropertyGetterDescriptor descriptor) {
|
||||
JsReturn returnExpression = new JsReturn(backingFieldReference(context(), property));
|
||||
JsFunction getterFunction = functionWithScope(context().getScopeForDescriptor(descriptor));
|
||||
getterFunction.setBody(AstUtil.convertToBlock(returnExpression));
|
||||
return getterFunction;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsPropertyInitializer generateDefaultSetter() {
|
||||
PropertySetterDescriptor setterDescriptor = property.getSetter();
|
||||
assert setterDescriptor != null : "Setter descriptor should not be null";
|
||||
return AstUtil.newNamedMethod(context().getNameForDescriptor(setterDescriptor),
|
||||
generateDefaultSetterFunction(setterDescriptor));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsFunction generateDefaultSetterFunction(@NotNull PropertySetterDescriptor propertySetterDescriptor) {
|
||||
JsFunction result = functionWithScope(context().getScopeForDescriptor(propertySetterDescriptor));
|
||||
JsParameter defaultParameter =
|
||||
new JsParameter(propertyAccessContext(propertySetterDescriptor).jsScope().declareTemporary());
|
||||
JsStatement assignment = assignmentToBackingField(context(), property, defaultParameter.getName().makeRef());
|
||||
result.setParameters(Arrays.asList(defaultParameter));
|
||||
result.setBody(AstUtil.convertToBlock(assignment));
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private TranslationContext propertyAccessContext(@NotNull PropertySetterDescriptor propertySetterDescriptor) {
|
||||
return context().newDeclaration(propertySetterDescriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsPropertyInitializer translateCustomAccessor(@NotNull JetPropertyAccessor expression) {
|
||||
return Translation.functionTranslator(expression, context()).translateAsMethod();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,420 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.expression;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.*;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.jet.lang.resolve.constants.NullValue;
|
||||
import org.jetbrains.k2js.translate.context.TemporaryVariable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.declaration.ClassTranslator;
|
||||
import org.jetbrains.k2js.translate.expression.foreach.ForTranslator;
|
||||
import org.jetbrains.k2js.translate.general.Translation;
|
||||
import org.jetbrains.k2js.translate.general.TranslatorVisitor;
|
||||
import org.jetbrains.k2js.translate.operation.BinaryOperationTranslator;
|
||||
import org.jetbrains.k2js.translate.operation.IncrementTranslator;
|
||||
import org.jetbrains.k2js.translate.operation.UnaryOperationTranslator;
|
||||
import org.jetbrains.k2js.translate.reference.*;
|
||||
import org.jetbrains.k2js.translate.utils.BindingUtils;
|
||||
import org.jetbrains.k2js.translate.utils.TranslationUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.*;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getObjectDeclarationName;
|
||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateInitializerForProperty;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
|
||||
|
||||
@NotNull
|
||||
private JsExpression translateAsExpression(@NotNull JetExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return AstUtil.convertToExpression(expression.accept(this, context));
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitConstantExpression(@NotNull JetConstantExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
CompileTimeConstant<?> compileTimeValue =
|
||||
context.bindingContext().get(BindingContext.COMPILE_TIME_VALUE, expression);
|
||||
assert compileTimeValue != null;
|
||||
if (compileTimeValue instanceof NullValue) {
|
||||
return context.program().getNullLiteral();
|
||||
}
|
||||
Object value = compileTimeValue.getValue();
|
||||
if (value instanceof Integer) {
|
||||
return context.program().getNumberLiteral((Integer) value);
|
||||
}
|
||||
if (value instanceof Boolean) {
|
||||
return context.program().getBooleanLiteral((Boolean) value);
|
||||
}
|
||||
|
||||
//TODO: test
|
||||
if (value instanceof Float) {
|
||||
return context.program().getNumberLiteral((Float) value);
|
||||
}
|
||||
if (value instanceof Double) {
|
||||
return context.program().getNumberLiteral((Double) value);
|
||||
}
|
||||
if (value instanceof String) {
|
||||
return context.program().getStringLiteral((String) value);
|
||||
}
|
||||
if (value instanceof Character) {
|
||||
return context.program().getStringLiteral(value.toString());
|
||||
}
|
||||
//TODO: all values
|
||||
throw new AssertionError("Unsupported constant expression" + expression.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitBlockExpression(@NotNull JetBlockExpression jetBlock, @NotNull TranslationContext context) {
|
||||
List<JetElement> statements = jetBlock.getStatements();
|
||||
JsBlock jsBlock = new JsBlock();
|
||||
TranslationContext blockContext = context.innerBlock(jsBlock);
|
||||
for (JetElement statement : statements) {
|
||||
assert statement instanceof JetExpression : "Elements in JetBlockExpression " +
|
||||
"should be of type JetExpression";
|
||||
JsNode jsNode = statement.accept(this, blockContext);
|
||||
jsBlock.addStatement(AstUtil.convertToStatement(jsNode));
|
||||
}
|
||||
return jsBlock;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitReturnExpression(@NotNull JetReturnExpression jetReturnExpression,
|
||||
@NotNull TranslationContext context) {
|
||||
JetExpression returnedExpression = jetReturnExpression.getReturnedExpression();
|
||||
if (returnedExpression != null) {
|
||||
JsExpression jsExpression = translateAsExpression(returnedExpression, context);
|
||||
return new JsReturn(jsExpression);
|
||||
}
|
||||
return new JsReturn();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitParenthesizedExpression(@NotNull JetParenthesizedExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
JetExpression expressionInside = expression.getExpression();
|
||||
if (expressionInside != null) {
|
||||
return expressionInside.accept(this, context);
|
||||
}
|
||||
return context.program().getEmptyStmt();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitBinaryExpression(@NotNull JetBinaryExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return BinaryOperationTranslator.translate(expression, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
// assume it is a local variable declaration
|
||||
public JsNode visitProperty(@NotNull JetProperty expression, @NotNull TranslationContext context) {
|
||||
DeclarationDescriptor descriptor = getDescriptorForElement(context.bindingContext(), expression);
|
||||
JsName jsPropertyName = context.getNameForDescriptor(descriptor);
|
||||
JsExpression jsInitExpression = translateInitializerForProperty(expression, context);
|
||||
return AstUtil.newVar(jsPropertyName, jsInitExpression);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitCallExpression(@NotNull JetCallExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return CallExpressionTranslator.translate(expression, null, CallType.NORMAL, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitIfExpression(@NotNull JetIfExpression expression, @NotNull TranslationContext context) {
|
||||
JsIf ifStatement = translateAsIfStatement(expression, context);
|
||||
if (BindingUtils.isStatement(context.bindingContext(), expression)) {
|
||||
return ifStatement;
|
||||
}
|
||||
TemporaryVariable result = context.declareTemporary(context.program().getNullLiteral());
|
||||
AstUtil.SaveLastExpressionMutator saveResultToTemporaryMutator =
|
||||
new AstUtil.SaveLastExpressionMutator(result.reference());
|
||||
JsNode mutatedIfStatement = AstUtil.mutateLastExpression(ifStatement,
|
||||
saveResultToTemporaryMutator);
|
||||
JsStatement resultingStatement = AstUtil.convertToStatement(mutatedIfStatement);
|
||||
context.addStatementToCurrentBlock(resultingStatement);
|
||||
return result.reference();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitSimpleNameExpression(@NotNull JetSimpleNameExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return ReferenceTranslator.translateSimpleName(expression, context);
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
private JsIf translateAsIfStatement(@NotNull JetIfExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
JsIf result = new JsIf();
|
||||
result.setIfExpr(translateConditionExpression(expression.getCondition(), context));
|
||||
result.setThenStmt(translateNullableExpressionAsNotNullStatement(expression.getThen(), context));
|
||||
result.setElseStmt(translateElseAsStatement(expression, context));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private JsStatement translateElseAsStatement(@NotNull JetIfExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
JetExpression jetElse = expression.getElse();
|
||||
if (jetElse == null) {
|
||||
return null;
|
||||
}
|
||||
return AstUtil.convertToStatement(jetElse.accept(this, context));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsStatement translateNullableExpressionAsNotNullStatement(@Nullable JetExpression nullableExpression,
|
||||
@NotNull TranslationContext context) {
|
||||
if (nullableExpression == null) {
|
||||
return context.program().getEmptyStmt();
|
||||
}
|
||||
return AstUtil.convertToStatement(nullableExpression.accept(this, context));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression translateConditionExpression(@Nullable JetExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
JsExpression jsCondition = translateNullableExpression(expression, context);
|
||||
assert (jsCondition != null) : "Condition should not be empty";
|
||||
return AstUtil.convertToExpression(jsCondition);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private JsExpression translateNullableExpression(@Nullable JetExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
if (expression == null) {
|
||||
return null;
|
||||
}
|
||||
return translateAsExpression(expression, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitWhileExpression(@NotNull JetWhileExpression expression, @NotNull TranslationContext context) {
|
||||
JsWhile result = new JsWhile();
|
||||
result.setCondition(translateConditionExpression(expression.getCondition(), context));
|
||||
result.setBody(translateNullableExpressionAsNotNullStatement(expression.getBody(), context));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitDoWhileExpression(@NotNull JetDoWhileExpression expression, @NotNull TranslationContext context) {
|
||||
JsDoWhile result = new JsDoWhile();
|
||||
result.setCondition(translateConditionExpression(expression.getCondition(), context));
|
||||
result.setBody(translateNullableExpressionAsNotNullStatement(expression.getBody(), context));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitStringTemplateExpression(@NotNull JetStringTemplateExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
JsStringLiteral stringLiteral = resolveAsStringConstant(expression, context);
|
||||
if (stringLiteral != null) {
|
||||
return stringLiteral;
|
||||
}
|
||||
return resolveAsTemplate(expression, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsNode resolveAsTemplate(@NotNull JetStringTemplateExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return StringTemplateTranslator.translate(expression, context);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private JsStringLiteral resolveAsStringConstant(@NotNull JetExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
Object value = getCompileTimeValue(context.bindingContext(), expression);
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
assert value instanceof String : "Compile time constant template should be a String constant.";
|
||||
String constantString = (String) value;
|
||||
return context.program().getStringLiteral(constantString);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitDotQualifiedExpression(@NotNull JetDotQualifiedExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return QualifiedExpressionTranslator.translateQualifiedExpression(expression, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitPrefixExpression(@NotNull JetPrefixExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return UnaryOperationTranslator.translate(expression, context);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitPostfixExpression(@NotNull JetPostfixExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return IncrementTranslator.translate(expression, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitIsExpression(@NotNull JetIsExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return Translation.patternTranslator(context).translateIsExpression(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitSafeQualifiedExpression(@NotNull JetSafeQualifiedExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return QualifiedExpressionTranslator.translateQualifiedExpression(expression, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitWhenExpression(@NotNull JetWhenExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return Translation.translateWhenExpression(expression, context);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitBinaryWithTypeRHSExpression(@NotNull JetBinaryExpressionWithTypeRHS expression,
|
||||
@NotNull TranslationContext context) {
|
||||
// we actually do not care for types in js
|
||||
return Translation.translateExpression(expression.getLeft(), context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitBreakExpression(@NotNull JetBreakExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return new JsBreak();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitContinueExpression(@NotNull JetContinueExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return new JsContinue();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitFunctionLiteralExpression(@NotNull JetFunctionLiteralExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return Translation.functionTranslator(expression, context).translateAsLiteral();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitThisExpression(@NotNull JetThisExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
DeclarationDescriptor descriptor =
|
||||
getDescriptorForReferenceExpression(context.bindingContext(), expression.getInstanceReference());
|
||||
return TranslationUtils.getThisObject(context, descriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitArrayAccessExpression(@NotNull JetArrayAccessExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return AccessTranslator.translateAsGet(expression, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitForExpression(@NotNull JetForExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return ForTranslator.translate(expression, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitTryExpression(@NotNull JetTryExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return TryTranslator.translate(expression, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitTupleExpression(@NotNull JetTupleExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
JsArrayLiteral result = new JsArrayLiteral();
|
||||
for (JetExpression entry : expression.getEntries()) {
|
||||
result.getExpressions().add(Translation.translateAsExpression(entry, context));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitThrowExpression(@NotNull JetThrowExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
JetExpression thrownExpression = expression.getThrownExpression();
|
||||
assert thrownExpression != null : "Thrown expression must not be null";
|
||||
return new JsThrow(translateAsExpression(thrownExpression, context));
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitObjectLiteralExpression(@NotNull JetObjectLiteralExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return ClassTranslator.generateClassCreationExpression(expression.getObjectDeclaration(), context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitObjectDeclaration(@NotNull JetObjectDeclaration expression,
|
||||
@NotNull TranslationContext context) {
|
||||
JetObjectDeclarationName objectDeclarationName = getObjectDeclarationName(expression);
|
||||
DeclarationDescriptor descriptor = getDescriptorForElement(context.bindingContext(), objectDeclarationName);
|
||||
JsName propertyName = context.getNameForDescriptor(descriptor);
|
||||
JsExpression value = ClassTranslator.generateClassCreationExpression(expression, context);
|
||||
return AstUtil.newVar(propertyName, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode visitNamedFunction(@NotNull JetNamedFunction function,
|
||||
@NotNull TranslationContext context) {
|
||||
return FunctionTranslator.newInstance(function, context).translateAsLocalFunction();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.expression;
|
||||
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.*;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.types.JetStandardClasses;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.k2js.translate.context.Namer;
|
||||
import org.jetbrains.k2js.translate.context.TemporaryVariable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
import org.jetbrains.k2js.translate.general.Translation;
|
||||
import org.jetbrains.k2js.translate.utils.DescriptorUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptor;
|
||||
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.*;
|
||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.*;
|
||||
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class FunctionTranslator extends AbstractTranslator {
|
||||
|
||||
@NotNull
|
||||
public static FunctionTranslator newInstance(@NotNull JetDeclarationWithBody function,
|
||||
@NotNull TranslationContext context) {
|
||||
return new FunctionTranslator(function, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final JetDeclarationWithBody functionDeclaration;
|
||||
@NotNull
|
||||
private final JsFunction functionObject;
|
||||
@NotNull
|
||||
private final TranslationContext functionBodyContext;
|
||||
@NotNull
|
||||
private final FunctionDescriptor descriptor;
|
||||
// function body needs to be explicitly created here to include it in the context
|
||||
@NotNull
|
||||
private final JsBlock functionBody;
|
||||
|
||||
private FunctionTranslator(@NotNull JetDeclarationWithBody functionDeclaration,
|
||||
@NotNull TranslationContext context) {
|
||||
super(context);
|
||||
this.functionBody = new JsBlock();
|
||||
this.descriptor = getFunctionDescriptor(context.bindingContext(), functionDeclaration);
|
||||
this.functionDeclaration = functionDeclaration;
|
||||
this.functionObject = createFunctionObject();
|
||||
this.functionBodyContext = functionBodyContext().innerBlock(functionBody);
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
public JsFunction translateAsLocalFunction() {
|
||||
JsName functionName = context().getNameForElement(functionDeclaration);
|
||||
JsFunction function = generateFunctionObject();
|
||||
function.setName(functionName);
|
||||
return function;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsPropertyInitializer translateAsMethod() {
|
||||
JsName functionName = context().getNameForElement(functionDeclaration);
|
||||
JsFunction function = generateFunctionObject();
|
||||
return new JsPropertyInitializer(functionName.makeRef(), function);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsExpression translateAsLiteral() {
|
||||
assert getExpectedThisDescriptor(descriptor) == null;
|
||||
ClassDescriptor containingClass = getContainingClass(descriptor);
|
||||
if (containingClass == null) {
|
||||
return generateFunctionObject();
|
||||
}
|
||||
return generateFunctionObjectWithAliasedThisReference(containingClass);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression generateFunctionObjectWithAliasedThisReference(@NotNull ClassDescriptor containingClass) {
|
||||
TemporaryVariable aliasForThis = newAliasForThis(context(), containingClass);
|
||||
JsFunction function = generateFunctionObject();
|
||||
removeAliasForThis(context(), containingClass);
|
||||
return AstUtil.newSequence(aliasForThis.assignmentExpression(), function);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsFunction generateFunctionObject() {
|
||||
functionObject.setParameters(translateParameters());
|
||||
translateBody();
|
||||
functionObject.setBody(functionBody);
|
||||
restoreContext();
|
||||
return functionObject;
|
||||
}
|
||||
|
||||
private void restoreContext() {
|
||||
if (isExtensionFunction()) {
|
||||
DeclarationDescriptor expectedReceiverDescriptor = getExpectedReceiverDescriptor(descriptor);
|
||||
assert expectedReceiverDescriptor != null : "Extension functions should always have receiver descriptors.";
|
||||
functionBodyContext.aliaser().removeAliasForThis(expectedReceiverDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsFunction createFunctionObject() {
|
||||
if (isDeclaration()) {
|
||||
return functionWithScope(context().getScopeForDescriptor(descriptor));
|
||||
}
|
||||
if (isLiteral()) {
|
||||
//TODO: changing this piece of code to more natural "same as for declaration" results in life test failing
|
||||
//TODO: must investigate
|
||||
return new JsFunction(context().jsScope());
|
||||
}
|
||||
throw new AssertionError("Unsupported type of functionDeclaration.");
|
||||
}
|
||||
|
||||
private void translateBody() {
|
||||
JetExpression jetBodyExpression = functionDeclaration.getBodyExpression();
|
||||
if (jetBodyExpression == null) {
|
||||
assert descriptor.getModality().equals(Modality.ABSTRACT);
|
||||
return;
|
||||
}
|
||||
JsNode realBody = Translation.translateExpression(jetBodyExpression, functionBodyContext);
|
||||
functionBody.addStatement(wrapWithReturnIfNeeded(realBody, mustAddReturnToGeneratedFunctionBody()));
|
||||
}
|
||||
|
||||
private boolean mustAddReturnToGeneratedFunctionBody() {
|
||||
JetType functionReturnType = descriptor.getReturnType();
|
||||
assert functionReturnType != null : "Function return typed type must be resolved.";
|
||||
return (!functionDeclaration.hasBlockBody()) && (!JetStandardClasses.isUnit(functionReturnType));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsBlock wrapWithReturnIfNeeded(@NotNull JsNode body, boolean needsReturn) {
|
||||
if (!needsReturn) {
|
||||
return AstUtil.convertToBlock(body);
|
||||
}
|
||||
return AstUtil.convertToBlock(lastExpressionReturned(body));
|
||||
}
|
||||
|
||||
private JsNode lastExpressionReturned(@NotNull JsNode body) {
|
||||
return AstUtil.mutateLastExpression(body, new AstUtil.Mutator() {
|
||||
@Override
|
||||
@NotNull
|
||||
public JsNode mutate(@NotNull JsNode node) {
|
||||
if (!(node instanceof JsExpression)) {
|
||||
return node;
|
||||
}
|
||||
return new JsReturn((JsExpression) node);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private TranslationContext functionBodyContext() {
|
||||
if (isLiteral()) {
|
||||
return context().innerJsScope(functionObject.getScope());
|
||||
} else {
|
||||
return context().newDeclaration(functionDeclaration);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<JsParameter> translateParameters() {
|
||||
List<JsParameter> jsParameters = new ArrayList<JsParameter>();
|
||||
mayBeAddThisParameterForExtensionFunction(jsParameters);
|
||||
for (ValueParameterDescriptor valueParameter : descriptor.getValueParameters()) {
|
||||
JsName parameterName = declareParameter(valueParameter);
|
||||
jsParameters.add(new JsParameter(parameterName));
|
||||
}
|
||||
return jsParameters;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsName declareParameter(@NotNull ValueParameterDescriptor valueParameter) {
|
||||
return context().getNameForDescriptor(valueParameter);
|
||||
}
|
||||
|
||||
private void mayBeAddThisParameterForExtensionFunction(@NotNull List<JsParameter> jsParameters) {
|
||||
if (isExtensionFunction()) {
|
||||
JsName receiver = functionBodyContext.jsScope().declareName(Namer.getReceiverParameterName());
|
||||
DeclarationDescriptor expectedReceiverDescriptor = getExpectedReceiverDescriptor(descriptor);
|
||||
assert expectedReceiverDescriptor != null;
|
||||
aliaser().setAliasForThis(expectedReceiverDescriptor, receiver);
|
||||
jsParameters.add(new JsParameter(receiver));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isExtensionFunction() {
|
||||
return DescriptorUtils.isExtensionFunction(descriptor) && !isLiteral();
|
||||
}
|
||||
|
||||
private boolean isLiteral() {
|
||||
return functionDeclaration instanceof JetFunctionLiteralExpression;
|
||||
}
|
||||
|
||||
private boolean isDeclaration() {
|
||||
return (functionDeclaration instanceof JetNamedFunction) ||
|
||||
(functionDeclaration instanceof JetPropertyAccessor);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.expression;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.backend.js.ast.JsInvocation;
|
||||
import com.google.dart.compiler.backend.js.ast.JsName;
|
||||
import com.google.dart.compiler.backend.js.ast.JsNameRef;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
import org.jetbrains.k2js.translate.general.Translation;
|
||||
import org.jetbrains.k2js.translate.utils.BindingUtils;
|
||||
import org.jetbrains.k2js.translate.utils.TranslationUtils;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class PatternTranslator extends AbstractTranslator {
|
||||
|
||||
@NotNull
|
||||
public static PatternTranslator newInstance(@NotNull TranslationContext context) {
|
||||
return new PatternTranslator(context);
|
||||
}
|
||||
|
||||
private PatternTranslator(@NotNull TranslationContext context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsExpression translateIsExpression(@NotNull JetIsExpression expression) {
|
||||
JsExpression left = Translation.translateAsExpression(expression.getLeftHandSide(), context());
|
||||
JetPattern pattern = getPattern(expression);
|
||||
JsExpression resultingExpression = translatePattern(pattern, left);
|
||||
if (expression.isNegated()) {
|
||||
return AstUtil.negated(resultingExpression);
|
||||
}
|
||||
return resultingExpression;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JetPattern getPattern(@NotNull JetIsExpression expression) {
|
||||
JetPattern pattern = expression.getPattern();
|
||||
assert pattern != null : "Pattern should not be null";
|
||||
return pattern;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsExpression translatePattern(@NotNull JetPattern pattern, @NotNull JsExpression expressionToMatch) {
|
||||
if (pattern instanceof JetTypePattern) {
|
||||
return translateTypePattern(expressionToMatch, (JetTypePattern) pattern);
|
||||
}
|
||||
if (pattern instanceof JetExpressionPattern) {
|
||||
return translateExpressionPattern(expressionToMatch, (JetExpressionPattern) pattern);
|
||||
}
|
||||
throw new AssertionError("Unsupported pattern type " + pattern.getClass());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression translateTypePattern(@NotNull JsExpression expressionToMatch,
|
||||
@NotNull JetTypePattern pattern) {
|
||||
//TODO: look into using intrinsics or other mechanisms to implement this logic
|
||||
JsName className = getClassReference(pattern).getName();
|
||||
if (className.getIdent().equals("String")) {
|
||||
return AstUtil.typeof(expressionToMatch, program().getStringLiteral("string"));
|
||||
}
|
||||
if (className.getIdent().equals("Int")) {
|
||||
return AstUtil.typeof(expressionToMatch, program().getStringLiteral("number"));
|
||||
}
|
||||
|
||||
JsInvocation isCheck = AstUtil.newInvocation(context().namer().isOperationReference(),
|
||||
expressionToMatch, getClassReference(pattern));
|
||||
if (isNullable(pattern)) {
|
||||
return addNullCheck(expressionToMatch, isCheck);
|
||||
}
|
||||
return isCheck;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression addNullCheck(@NotNull JsExpression expressionToMatch, @NotNull JsInvocation isCheck) {
|
||||
return AstUtil.or(TranslationUtils.isNullCheck(context(), expressionToMatch), isCheck);
|
||||
}
|
||||
|
||||
private boolean isNullable(JetTypePattern pattern) {
|
||||
return BindingUtils.getTypeByReference(bindingContext(),
|
||||
getTypeReference(pattern)).isNullable();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsNameRef getClassReference(@NotNull JetTypePattern pattern) {
|
||||
JetTypeReference typeReference = getTypeReference(pattern);
|
||||
return getClassNameReferenceForTypeReference(typeReference);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JetTypeReference getTypeReference(@NotNull JetTypePattern pattern) {
|
||||
JetTypeReference typeReference = pattern.getTypeReference();
|
||||
assert typeReference != null : "Type pattern should contain a type reference";
|
||||
return typeReference;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsNameRef getClassNameReferenceForTypeReference(@NotNull JetTypeReference typeReference) {
|
||||
ClassDescriptor referencedClass = BindingUtils.getClassDescriptorForTypeReference
|
||||
(bindingContext(), typeReference);
|
||||
return TranslationUtils.getQualifiedReference(context(), referencedClass);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression translateExpressionPattern(JsExpression expressionToMatch, JetExpressionPattern pattern) {
|
||||
JetExpression patternExpression = pattern.getExpression();
|
||||
assert patternExpression != null : "Expression patter should have an expression.";
|
||||
JsExpression expressionToMatchAgainst =
|
||||
Translation.translateAsExpression(patternExpression, context());
|
||||
return AstUtil.equals(expressionToMatch, expressionToMatchAgainst);
|
||||
}
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.expression;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.backend.js.ast.JsStringLiteral;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
import org.jetbrains.k2js.translate.general.Translation;
|
||||
|
||||
import static com.google.dart.compiler.util.AstUtil.sum;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
//TODO: add toString call for non-primitive object
|
||||
public final class StringTemplateTranslator extends AbstractTranslator {
|
||||
|
||||
@NotNull
|
||||
public static JsExpression translate(@NotNull JetStringTemplateExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return (new StringTemplateTranslator(expression, context).translate());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final JetStringTemplateExpression expression;
|
||||
|
||||
private StringTemplateTranslator(@NotNull JetStringTemplateExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
super(context);
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression translate() {
|
||||
assert expression.getEntries().length != 0 : "String template must have one or more entries.";
|
||||
EntryVisitor entryVisitor = new EntryVisitor();
|
||||
for (JetStringTemplateEntry entry : expression.getEntries()) {
|
||||
entry.accept(entryVisitor);
|
||||
}
|
||||
return entryVisitor.getResultingExpression();
|
||||
}
|
||||
|
||||
private final class EntryVisitor extends JetVisitorVoid {
|
||||
|
||||
@Nullable
|
||||
private JsExpression resultingExpression = null;
|
||||
|
||||
void append(@NotNull JsExpression expression) {
|
||||
if (resultingExpression == null) {
|
||||
resultingExpression = expression;
|
||||
} else {
|
||||
resultingExpression = sum(resultingExpression, expression);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitStringTemplateEntryWithExpression(@NotNull JetStringTemplateEntryWithExpression entry) {
|
||||
JetExpression entryExpression = entry.getExpression();
|
||||
assert entryExpression != null :
|
||||
"JetStringTemplateEntryWithExpression must have not null entry expression.";
|
||||
append(Translation.translateAsExpression(entryExpression, context()));
|
||||
}
|
||||
|
||||
//TODO: duplication
|
||||
@Override
|
||||
public void visitLiteralStringTemplateEntry(@NotNull JetLiteralStringTemplateEntry entry) {
|
||||
JsStringLiteral stringConstant = program().getStringLiteral(entry.getText());
|
||||
append(stringConstant);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEscapeStringTemplateEntry(@NotNull JetEscapeStringTemplateEntry entry) {
|
||||
JsStringLiteral escapedValue = program().getStringLiteral(entry.getUnescapedValue());
|
||||
append(escapedValue);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsExpression getResultingExpression() {
|
||||
assert resultingExpression != null;
|
||||
return resultingExpression;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.expression;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsBlock;
|
||||
import com.google.dart.compiler.backend.js.ast.JsCatch;
|
||||
import com.google.dart.compiler.backend.js.ast.JsName;
|
||||
import com.google.dart.compiler.backend.js.ast.JsTry;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
import org.jetbrains.k2js.translate.general.Translation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.google.dart.compiler.util.AstUtil.convertToBlock;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
//TODO: not tested at all
|
||||
//TODO: not implemented catch logic
|
||||
public final class TryTranslator extends AbstractTranslator {
|
||||
|
||||
@NotNull
|
||||
public static JsTry translate(@NotNull JetTryExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return (new TryTranslator(expression, context)).translate();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final JetTryExpression expression;
|
||||
|
||||
private TryTranslator(@NotNull JetTryExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
super(context);
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
private JsTry translate() {
|
||||
JsTry result = new JsTry();
|
||||
result.setTryBlock(translateTryBlock());
|
||||
result.setFinallyBlock(translateFinallyBlock());
|
||||
result.getCatches().addAll(translateCatches());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private JsBlock translateFinallyBlock() {
|
||||
JetFinallySection finallyBlock = expression.getFinallyBlock();
|
||||
if (finallyBlock == null) return null;
|
||||
|
||||
return convertToBlock(Translation.translateAsStatement(finallyBlock.getFinalExpression(), context()));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsBlock translateTryBlock() {
|
||||
return convertToBlock(Translation.translateAsStatement(expression.getTryBlock(), context()));
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
private List<JsCatch> translateCatches() {
|
||||
List<JsCatch> result = new ArrayList<JsCatch>();
|
||||
for (JetCatchClause catchClause : expression.getCatchClauses()) {
|
||||
result.add(translateCatchClause(catchClause));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsCatch translateCatchClause(@NotNull JetCatchClause catchClause) {
|
||||
JetParameter catchParameter = catchClause.getCatchParameter();
|
||||
assert catchParameter != null : "Valid catch must have a parameter.";
|
||||
|
||||
JsName parameterName = context().getNameForElement(catchParameter);
|
||||
JsCatch result = new JsCatch(context().jsScope(), parameterName.getIdent());
|
||||
result.setBody(translateCatchBody(catchClause));
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsBlock translateCatchBody(@NotNull JetCatchClause catchClause) {
|
||||
JetExpression catchBody = catchClause.getCatchBody();
|
||||
if (catchBody == null) {
|
||||
return convertToBlock(program().getEmptyStmt());
|
||||
}
|
||||
return convertToBlock(Translation.translateAsStatement(catchBody, context()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.expression;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.*;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.k2js.translate.context.TemporaryVariable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
import org.jetbrains.k2js.translate.general.Translation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public class WhenTranslator extends AbstractTranslator {
|
||||
|
||||
@NotNull
|
||||
static public JsNode translateWhenExpression(@NotNull JetWhenExpression expression, @NotNull TranslationContext context) {
|
||||
WhenTranslator translator = new WhenTranslator(expression, context);
|
||||
return translator.translate();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final JetWhenExpression whenExpression;
|
||||
@NotNull
|
||||
private final JsExpression expressionToMatch;
|
||||
@NotNull
|
||||
private final TemporaryVariable dummyCounter;
|
||||
@NotNull
|
||||
private final TemporaryVariable result;
|
||||
|
||||
private int currentEntryNumber = 0;
|
||||
|
||||
private WhenTranslator(@NotNull JetWhenExpression expression, @NotNull TranslationContext context) {
|
||||
super(context);
|
||||
this.whenExpression = expression;
|
||||
this.expressionToMatch = translateExpressionToMatch(whenExpression);
|
||||
this.dummyCounter = context.declareTemporary(program().getNumberLiteral(0));
|
||||
this.result = context.declareTemporary(program().getNullLiteral());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
JsNode translate() {
|
||||
JsFor resultingFor = generateDummyFor();
|
||||
List<JsStatement> entries = translateEntries();
|
||||
resultingFor.setBody(AstUtil.newBlock(entries));
|
||||
context().addStatementToCurrentBlock(resultingFor);
|
||||
return result.reference();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<JsStatement> translateEntries() {
|
||||
List<JsStatement> entries = new ArrayList<JsStatement>();
|
||||
for (JetWhenEntry entry : whenExpression.getEntries()) {
|
||||
entries.add(surroundWithDummyIf(translateEntry(entry)));
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsStatement surroundWithDummyIf(@NotNull JsStatement entryStatement) {
|
||||
JsExpression stepNumberEqualsCurrentEntryNumber = new JsBinaryOperation(JsBinaryOperator.EQ,
|
||||
dummyCounter.reference(), program().getNumberLiteral(currentEntryNumber));
|
||||
currentEntryNumber++;
|
||||
return new JsIf(stepNumberEqualsCurrentEntryNumber, entryStatement, null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsFor generateDummyFor() {
|
||||
JsFor result = new JsFor();
|
||||
result.setInitExpr(dummyCounter.assignmentExpression());
|
||||
result.setIncrExpr(generateIncrementStatement());
|
||||
result.setCondition(generateConditionStatement());
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsBinaryOperation generateConditionStatement() {
|
||||
JsNumberLiteral entriesNumber = program().getNumberLiteral(whenExpression.getEntries().size());
|
||||
return new JsBinaryOperation(JsBinaryOperator.LT, dummyCounter.reference(), entriesNumber);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsPrefixOperation generateIncrementStatement() {
|
||||
return new JsPrefixOperation(JsUnaryOperator.INC, dummyCounter.reference());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsStatement translateEntry(@NotNull JetWhenEntry entry) {
|
||||
JsStatement statementToExecute = withReturnValueCaptured(translateEntryExpression(entry));
|
||||
if (entry.isElse()) {
|
||||
return statementToExecute;
|
||||
}
|
||||
JsExpression condition = translateConditions(entry);
|
||||
return new JsIf(condition, addDummyBreak(statementToExecute), null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
JsStatement withReturnValueCaptured(@NotNull JsNode node) {
|
||||
|
||||
return AstUtil.convertToStatement(AstUtil.mutateLastExpression(node,
|
||||
new AstUtil.SaveLastExpressionMutator(result.reference())));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsNode translateEntryExpression(@NotNull JetWhenEntry entry) {
|
||||
JetExpression expressionToExecute = entry.getExpression();
|
||||
assert expressionToExecute != null : "WhenEntry should have whenExpression to execute.";
|
||||
return Translation.translateExpression(expressionToExecute, context());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression translateConditions(@NotNull JetWhenEntry entry) {
|
||||
List<JsExpression> conditions = new ArrayList<JsExpression>();
|
||||
for (JetWhenCondition condition : entry.getConditions()) {
|
||||
conditions.add(translateCondition(condition));
|
||||
}
|
||||
return anyOfThemIsTrue(conditions);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression anyOfThemIsTrue(List<JsExpression> conditions) {
|
||||
assert !conditions.isEmpty() : "When entry (not else) should have at least one condition";
|
||||
JsExpression current = null;
|
||||
for (JsExpression condition : conditions) {
|
||||
current = addCaseCondition(current, condition);
|
||||
}
|
||||
assert current != null;
|
||||
return current;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression addCaseCondition(@Nullable JsExpression current, @NotNull JsExpression condition) {
|
||||
if (current == null) {
|
||||
return condition;
|
||||
} else {
|
||||
return AstUtil.or(current, condition);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression translateCondition(@NotNull JetWhenCondition condition) {
|
||||
if ((condition instanceof JetWhenConditionIsPattern) || (condition instanceof JetWhenConditionWithExpression)) {
|
||||
return translatePatternCondition(condition);
|
||||
}
|
||||
throw new AssertionError("Unsupported when condition " + condition.getClass());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsBlock addDummyBreak(@NotNull JsStatement statement) {
|
||||
return AstUtil.newBlock(statement, new JsBreak());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression translatePatternCondition(@NotNull JetWhenCondition condition) {
|
||||
JsExpression patternMatchExpression = Translation.patternTranslator(context()).
|
||||
translatePattern(getPattern(condition), expressionToMatch);
|
||||
if (isNegated(condition)) {
|
||||
return AstUtil.negated(patternMatchExpression);
|
||||
}
|
||||
return patternMatchExpression;
|
||||
}
|
||||
|
||||
private boolean isNegated(@NotNull JetWhenCondition condition) {
|
||||
if (condition instanceof JetWhenConditionIsPattern) {
|
||||
return ((JetWhenConditionIsPattern) condition).isNegated();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JetPattern getPattern(@NotNull JetWhenCondition condition) {
|
||||
JetPattern pattern;
|
||||
if (condition instanceof JetWhenConditionIsPattern) {
|
||||
pattern = ((JetWhenConditionIsPattern) condition).getPattern();
|
||||
} else if (condition instanceof JetWhenConditionWithExpression) {
|
||||
pattern = ((JetWhenConditionWithExpression) condition).getPattern();
|
||||
} else {
|
||||
throw new AssertionError("Wrong type of JetWhenCondition");
|
||||
}
|
||||
assert pattern != null : "Condition should have a non null pattern.";
|
||||
return pattern;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression translateExpressionToMatch(@NotNull JetWhenExpression expression) {
|
||||
JetExpression subject = expression.getSubjectExpression();
|
||||
assert subject != null : "Subject should not be null.";
|
||||
return Translation.translateAsExpression(subject, context());
|
||||
}
|
||||
}
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.expression.foreach;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.*;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetForExpression;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.k2js.translate.context.TemporaryVariable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.Translation;
|
||||
import org.jetbrains.k2js.translate.intrinsic.string.LengthIntrinsic;
|
||||
import org.jetbrains.k2js.translate.utils.BindingUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.k2js.translate.expression.foreach.ForTranslatorUtils.temporariesInitialization;
|
||||
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.getClassDescriptorForType;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopBody;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopRange;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class ArrayForTranslator extends ForTranslator {
|
||||
|
||||
@NotNull
|
||||
public static JsStatement translate(@NotNull JetForExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return (new ArrayForTranslator(expression, context).translate());
|
||||
}
|
||||
|
||||
public static boolean isApplicable(@NotNull JetForExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
JetExpression loopRange = getLoopRange(expression);
|
||||
JetType rangeType = BindingUtils.getTypeForExpression(context.bindingContext(), loopRange);
|
||||
//TODO: better check
|
||||
//TODO: IMPORTANT!
|
||||
return getClassDescriptorForType(rangeType).getName().equals("Array")
|
||||
|| getClassDescriptorForType(rangeType).getName().equals("IntArray");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final TemporaryVariable loopRange;
|
||||
|
||||
@NotNull
|
||||
private final TemporaryVariable end;
|
||||
|
||||
@NotNull
|
||||
private final TemporaryVariable index;
|
||||
|
||||
private ArrayForTranslator(@NotNull JetForExpression forExpression, @NotNull TranslationContext context) {
|
||||
super(forExpression, context);
|
||||
loopRange = context.declareTemporary(Translation.translateAsExpression(getLoopRange(expression), context));
|
||||
JsExpression length = LengthIntrinsic.INSTANCE.apply(loopRange.reference(), Collections.<JsExpression>emptyList(), context());
|
||||
end = context().declareTemporary(length);
|
||||
index = context().declareTemporary(program().getNumberLiteral(0));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsBlock translate() {
|
||||
List<JsStatement> blockStatements = temporariesInitialization(loopRange, end);
|
||||
blockStatements.add(generateForExpression());
|
||||
return AstUtil.newBlock(blockStatements);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsFor generateForExpression() {
|
||||
JsFor result = new JsFor();
|
||||
result.setInitVars(initExpression());
|
||||
result.setCondition(getCondition());
|
||||
result.setIncrExpr(getIncrExpression());
|
||||
result.setBody(getBody());
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsStatement getBody() {
|
||||
JsArrayAccess arrayAccess = new JsArrayAccess(loopRange.reference(), index.reference());
|
||||
JsStatement currentVar = AstUtil.newVar(parameterName, arrayAccess);
|
||||
JsStatement realBody = Translation.translateAsStatement(getLoopBody(expression), context());
|
||||
return AstUtil.newBlock(currentVar, realBody);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsVars initExpression() {
|
||||
return AstUtil.newVar(index.name(), program().getNumberLiteral(0));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression getCondition() {
|
||||
return AstUtil.notEqual(index.reference(), end.reference());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression getIncrExpression() {
|
||||
return new JsPrefixOperation(JsUnaryOperator.INC, index.reference());
|
||||
}
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.expression.foreach;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsName;
|
||||
import com.google.dart.compiler.backend.js.ast.JsStatement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetForExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetParameter;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
import org.jetbrains.k2js.translate.general.Translation;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopBody;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopParameter;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
|
||||
//TODO: create util class for managing stuff like binary operations
|
||||
public abstract class ForTranslator extends AbstractTranslator {
|
||||
|
||||
@NotNull
|
||||
public static JsStatement translate(@NotNull JetForExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
if (RangeLiteralForTranslator.isApplicable(expression, context)) {
|
||||
return RangeLiteralForTranslator.translate(expression, context);
|
||||
}
|
||||
if (RangeForTranslator.isApplicable(expression, context)) {
|
||||
return RangeForTranslator.translate(expression, context);
|
||||
}
|
||||
if (ArrayForTranslator.isApplicable(expression, context)) {
|
||||
return ArrayForTranslator.translate(expression, context);
|
||||
}
|
||||
return IteratorForTranslator.translate(expression, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected final JetForExpression expression;
|
||||
@NotNull
|
||||
protected final JsName parameterName;
|
||||
|
||||
protected ForTranslator(@NotNull JetForExpression forExpression, @NotNull TranslationContext context) {
|
||||
super(context);
|
||||
this.expression = forExpression;
|
||||
this.parameterName = declareParameter();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsName declareParameter() {
|
||||
JetParameter loopParameter = getLoopParameter(expression);
|
||||
return context().getNameForElement(loopParameter);
|
||||
}
|
||||
|
||||
//TODO: look for should-be-usages
|
||||
@NotNull
|
||||
protected JsStatement translateOriginalBodyExpression() {
|
||||
return Translation.translateAsStatement(getLoopBody(expression), context());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.expression.foreach;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.dart.compiler.backend.js.ast.JsStatement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.k2js.translate.context.TemporaryVariable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
//TODO: consider moving some of the binary/unary operations stuff here
|
||||
public final class ForTranslatorUtils {
|
||||
|
||||
private ForTranslatorUtils() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<JsStatement> temporariesInitialization(@NotNull TemporaryVariable... temporaries) {
|
||||
List<JsStatement> result = Lists.newArrayList();
|
||||
for (TemporaryVariable temporary : temporaries) {
|
||||
result.add(temporary.assignmentExpression().makeStmt());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.expression.foreach;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.*;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetForExpression;
|
||||
import org.jetbrains.k2js.translate.context.TemporaryVariable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.Translation;
|
||||
import org.jetbrains.k2js.translate.reference.CallBuilder;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.*;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopBody;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopRange;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class IteratorForTranslator extends ForTranslator {
|
||||
|
||||
@NotNull
|
||||
public static JsStatement translate(@NotNull JetForExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return (new IteratorForTranslator(expression, context).translate());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final TemporaryVariable iterator;
|
||||
|
||||
private IteratorForTranslator(@NotNull JetForExpression forExpression, @NotNull TranslationContext context) {
|
||||
super(forExpression, context);
|
||||
iterator = context().declareTemporary(iteratorMethodInvocation());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsBlock translate() {
|
||||
JsBlock bodyBlock = generateCycleBody();
|
||||
JsWhile cycle = new JsWhile(hasNextMethodInvocation(), bodyBlock);
|
||||
return AstUtil.newBlock(iterator.assignmentExpression().makeStmt(), cycle);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsBlock generateCycleBody() {
|
||||
JsBlock cycleBody = new JsBlock();
|
||||
JsStatement parameterAssignment = AstUtil.newVar(parameterName, nextMethodInvocation());
|
||||
JsNode originalBody = Translation.translateExpression(getLoopBody(expression), context().innerBlock(cycleBody));
|
||||
cycleBody.addStatement(parameterAssignment);
|
||||
cycleBody.addStatement(AstUtil.convertToBlock(originalBody));
|
||||
return cycleBody;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression nextMethodInvocation() {
|
||||
FunctionDescriptor nextFunction = getNextFunction(bindingContext(), getLoopRange(expression));
|
||||
return translateMethodInvocation(iterator.reference(), nextFunction);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression hasNextMethodInvocation() {
|
||||
CallableDescriptor hasNextFunction = getHasNextCallable(bindingContext(), getLoopRange(expression));
|
||||
return translateMethodInvocation(iterator.reference(), hasNextFunction);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression iteratorMethodInvocation() {
|
||||
JetExpression rangeExpression = getLoopRange(expression);
|
||||
JsExpression range = Translation.translateAsExpression(rangeExpression, context());
|
||||
FunctionDescriptor iteratorFunction = getIteratorFunction(bindingContext(), rangeExpression);
|
||||
return translateMethodInvocation(range, iteratorFunction);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression translateMethodInvocation(@Nullable JsExpression receiver,
|
||||
@NotNull CallableDescriptor descriptor) {
|
||||
return CallBuilder.build(context())
|
||||
.receiver(receiver)
|
||||
.descriptor(descriptor)
|
||||
.translate();
|
||||
}
|
||||
}
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.expression.foreach;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.*;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetForExpression;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.k2js.translate.context.TemporaryVariable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.Translation;
|
||||
import org.jetbrains.k2js.translate.utils.BindingUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.k2js.translate.expression.foreach.ForTranslatorUtils.temporariesInitialization;
|
||||
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.getClassDescriptorForType;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopBody;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopRange;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class RangeForTranslator extends ForTranslator {
|
||||
|
||||
@NotNull
|
||||
public static JsStatement translate(@NotNull JetForExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return (new RangeForTranslator(expression, context).translate());
|
||||
}
|
||||
|
||||
public static boolean isApplicable(@NotNull JetForExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
JetExpression loopRange = getLoopRange(expression);
|
||||
JetType rangeType = BindingUtils.getTypeForExpression(context.bindingContext(), loopRange);
|
||||
//TODO: better check
|
||||
return getClassDescriptorForType(rangeType).getName().equals("IntRange");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final TemporaryVariable rangeExpression;
|
||||
@NotNull
|
||||
private final TemporaryVariable incrVar;
|
||||
@NotNull
|
||||
private final TemporaryVariable start;
|
||||
@NotNull
|
||||
private final TemporaryVariable end;
|
||||
|
||||
private RangeForTranslator(@NotNull JetForExpression forExpression, @NotNull TranslationContext context) {
|
||||
super(forExpression, context);
|
||||
rangeExpression = context.declareTemporary(Translation.translateAsExpression(getLoopRange(expression), context));
|
||||
JsExpression isReversed = callFunction("get_reversed");
|
||||
JsConditional incrVarValue = new JsConditional(isReversed,
|
||||
program().getNumberLiteral(-1),
|
||||
program().getNumberLiteral(1));
|
||||
incrVar = context().declareTemporary(incrVarValue);
|
||||
start = context().declareTemporary(callFunction("get_start"));
|
||||
end = context().declareTemporary(new JsBinaryOperation(JsBinaryOperator.ADD, callFunction("get_end"), incrVar.reference()));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsBlock translate() {
|
||||
List<JsStatement> blockStatements = temporariesInitialization(rangeExpression, incrVar, start, end);
|
||||
blockStatements.add(generateForExpression());
|
||||
return AstUtil.newBlock(blockStatements);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsFor generateForExpression() {
|
||||
JsFor result = new JsFor();
|
||||
result.setInitVars(initExpression());
|
||||
result.setCondition(getCondition());
|
||||
result.setIncrExpr(getIncrExpression());
|
||||
result.setBody(Translation.translateAsStatement(getLoopBody(expression), context()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsVars initExpression() {
|
||||
return AstUtil.newVar(parameterName, start.reference());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression getCondition() {
|
||||
return AstUtil.notEqual(parameterName.makeRef(), end.reference());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression getIncrExpression() {
|
||||
return new JsBinaryOperation(JsBinaryOperator.ASG_ADD, parameterName.makeRef(), incrVar.reference());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression getField(@NotNull String fieldName) {
|
||||
JsNameRef nameRef = AstUtil.newQualifiedNameRef(fieldName);
|
||||
AstUtil.setQualifier(nameRef, rangeExpression.reference());
|
||||
return nameRef;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression callFunction(@NotNull String funName) {
|
||||
return AstUtil.newInvocation(getField(funName));
|
||||
}
|
||||
}
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.expression.foreach;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.dart.compiler.backend.js.ast.*;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetBinaryExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetForExpression;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
import org.jetbrains.k2js.translate.context.TemporaryVariable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.k2js.translate.expression.foreach.ForTranslatorUtils.temporariesInitialization;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getLoopRange;
|
||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateLeftExpression;
|
||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateRightExpression;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
|
||||
// TODO: implement reverse semantics
|
||||
public final class RangeLiteralForTranslator extends ForTranslator {
|
||||
|
||||
@NotNull
|
||||
public static JsStatement translate(@NotNull JetForExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return (new RangeLiteralForTranslator(expression, context).translate());
|
||||
}
|
||||
|
||||
public static boolean isApplicable(@NotNull JetForExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
JetExpression loopRange = getLoopRange(expression);
|
||||
if (!(loopRange instanceof JetBinaryExpression)) {
|
||||
return false;
|
||||
}
|
||||
boolean isRangeToOperation = ((JetBinaryExpression) loopRange).getOperationToken() == JetTokens.RANGE;
|
||||
return isRangeToOperation && RangeForTranslator.isApplicable(expression, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final JsExpression rangeStart;
|
||||
|
||||
@NotNull
|
||||
private final TemporaryVariable rangeEnd;
|
||||
|
||||
private RangeLiteralForTranslator(@NotNull JetForExpression forExpression, @NotNull TranslationContext context) {
|
||||
super(forExpression, context);
|
||||
JetExpression loopRange = getLoopRange(expression);
|
||||
assert loopRange instanceof JetBinaryExpression;
|
||||
JetBinaryExpression loopRangeAsBinary = ((JetBinaryExpression) loopRange);
|
||||
rangeStart = translateLeftExpression(context, loopRangeAsBinary);
|
||||
rangeEnd = context.declareTemporary(getRangeEnd(loopRangeAsBinary));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression getRangeEnd(@NotNull JetBinaryExpression loopRangeAsBinary) {
|
||||
JsExpression rightExpression = translateRightExpression(context(), loopRangeAsBinary);
|
||||
return new JsBinaryOperation(JsBinaryOperator.ADD, rightExpression, program().getNumberLiteral(1));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsBlock translate() {
|
||||
List<JsStatement> blockStatements = temporariesInitialization(rangeEnd);
|
||||
blockStatements.add(generateForExpression());
|
||||
return AstUtil.newBlock(blockStatements);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsFor generateForExpression() {
|
||||
JsFor result = new JsFor();
|
||||
result.setInitVars(initExpression());
|
||||
result.setCondition(getCondition());
|
||||
result.setIncrExpr(getIncrExpression());
|
||||
result.setBody(translateOriginalBodyExpression());
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsVars initExpression() {
|
||||
return AstUtil.newVar(parameterName, rangeStart);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression getCondition() {
|
||||
return AstUtil.notEqual(parameterName.makeRef(), rangeEnd.reference());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression getIncrExpression() {
|
||||
return new JsPrefixOperation(JsUnaryOperator.INC, parameterName.makeRef());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.general;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsProgram;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.k2js.translate.context.Aliaser;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public abstract class AbstractTranslator {
|
||||
|
||||
@NotNull
|
||||
private final TranslationContext context;
|
||||
|
||||
protected AbstractTranslator(@NotNull TranslationContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected JsProgram program() {
|
||||
return context.program();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected TranslationContext context() {
|
||||
return context;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected Aliaser aliaser() {
|
||||
return context.aliaser();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected BindingContext bindingContext() {
|
||||
return context.bindingContext();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.general;
|
||||
|
||||
import com.google.dart.compiler.backend.js.JsNamer;
|
||||
import com.google.dart.compiler.backend.js.JsPrettyNamer;
|
||||
import com.google.dart.compiler.backend.js.ast.*;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.types.JetStandardLibrary;
|
||||
import org.jetbrains.k2js.translate.context.StaticContext;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.declaration.ClassTranslator;
|
||||
import org.jetbrains.k2js.translate.declaration.NamespaceDeclarationTranslator;
|
||||
import org.jetbrains.k2js.translate.expression.ExpressionVisitor;
|
||||
import org.jetbrains.k2js.translate.expression.FunctionTranslator;
|
||||
import org.jetbrains.k2js.translate.expression.PatternTranslator;
|
||||
import org.jetbrains.k2js.translate.expression.WhenTranslator;
|
||||
import org.jetbrains.k2js.translate.initializer.ClassInitializerTranslator;
|
||||
import org.jetbrains.k2js.translate.initializer.NamespaceInitializerTranslator;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
* <p/>
|
||||
* This class provides a interface which all translators use to interact with each other.
|
||||
* Goal is to simlify interaction between translators.
|
||||
*/
|
||||
public final class Translation {
|
||||
|
||||
@NotNull
|
||||
public static FunctionTranslator functionTranslator(@NotNull JetDeclarationWithBody function,
|
||||
@NotNull TranslationContext context) {
|
||||
return FunctionTranslator.newInstance(function, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<JsStatement> translateFiles(@NotNull List<JetFile> files, @NotNull TranslationContext context) {
|
||||
return NamespaceDeclarationTranslator.translateFiles(files, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsInvocation translateClassDeclaration(@NotNull JetClass classDeclaration,
|
||||
@NotNull TranslationContext context) {
|
||||
return ClassTranslator.generateClassCreationExpression(classDeclaration, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static PatternTranslator patternTranslator(@NotNull TranslationContext context) {
|
||||
return PatternTranslator.newInstance(context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsNode translateExpression(@NotNull JetExpression expression, @NotNull TranslationContext context) {
|
||||
return expression.accept(new ExpressionVisitor(), context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression translateAsExpression(@NotNull JetExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return AstUtil.convertToExpression(translateExpression(expression, context));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsStatement translateAsStatement(@NotNull JetExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return AstUtil.convertToStatement(translateExpression(expression, context));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsNode translateWhenExpression(@NotNull JetWhenExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return WhenTranslator.translateWhenExpression(expression, context);
|
||||
}
|
||||
|
||||
//TODO: see if generate*Initializer methods fit somewhere else
|
||||
@NotNull
|
||||
public static JsPropertyInitializer generateClassInitializerMethod(@NotNull JetClassOrObject classDeclaration,
|
||||
@NotNull TranslationContext context) {
|
||||
return (new ClassInitializerTranslator(classDeclaration, context)).generateInitializeMethod();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsPropertyInitializer generateNamespaceInitializerMethod(@NotNull NamespaceDescriptor namespace,
|
||||
@NotNull TranslationContext context) {
|
||||
return (new NamespaceInitializerTranslator(namespace, context)).generateInitializeMethod();
|
||||
}
|
||||
|
||||
public static JsProgram generateAst(@NotNull BindingContext bindingContext,
|
||||
@NotNull List<JetFile> files) {
|
||||
//TODO: move some of the code somewhere
|
||||
JetStandardLibrary standardLibrary = JetStandardLibrary.getInstance();
|
||||
StaticContext staticContext = StaticContext.generateStaticContext(standardLibrary, bindingContext);
|
||||
JsBlock block = staticContext.getProgram().getFragmentBlock(0);
|
||||
TranslationContext context = TranslationContext.rootContext(staticContext);
|
||||
block.getStatements().addAll(Translation.translateFiles(files, context));
|
||||
JsNamer namer = new JsPrettyNamer();
|
||||
namer.exec(context.program());
|
||||
return context.program();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.general;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
import org.jetbrains.jet.lang.psi.JetVisitor;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
* <p/>
|
||||
* This class is a base class for all visitors.
|
||||
*/
|
||||
public class TranslatorVisitor<T> extends JetVisitor<T, TranslationContext> {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public T visitJetElement(JetElement expression, TranslationContext context) {
|
||||
throw new UnsupportedOperationException("Unsupported expression encountered:" + expression.toString());
|
||||
}
|
||||
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.initializer;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsFunction;
|
||||
import com.google.dart.compiler.backend.js.ast.JsPropertyInitializer;
|
||||
import com.google.dart.compiler.backend.js.ast.JsStatement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetClassOrObject;
|
||||
import org.jetbrains.k2js.translate.context.Namer;
|
||||
import org.jetbrains.k2js.translate.context.NamingScope;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public abstract class AbstractInitializerTranslator extends AbstractTranslator {
|
||||
|
||||
@NotNull
|
||||
private final InitializerVisitor visitor;
|
||||
@NotNull
|
||||
protected final NamingScope initializerMethodScope;
|
||||
|
||||
protected AbstractInitializerTranslator(@NotNull NamingScope scope, @NotNull TranslationContext context) {
|
||||
super(context.contextWithScope(scope));
|
||||
this.visitor = new InitializerVisitor();
|
||||
this.initializerMethodScope = scope;
|
||||
}
|
||||
|
||||
abstract protected JsFunction generateInitializerFunction();
|
||||
|
||||
@NotNull
|
||||
public JsPropertyInitializer generateInitializeMethod() {
|
||||
JsPropertyInitializer initializer = new JsPropertyInitializer();
|
||||
initializer.setLabelExpr(Namer.initializeMethodReference());
|
||||
initializer.setValueExpr(generateInitializerFunction());
|
||||
return initializer;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected List<JsStatement> translateClassInitializers(@NotNull JetClassOrObject declaration) {
|
||||
return visitor.traverseClass(declaration, context());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected List<JsStatement> translateNamespaceInitializers(@NotNull NamespaceDescriptor namespace) {
|
||||
return visitor.traverseNamespace(namespace, context());
|
||||
|
||||
}
|
||||
}
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.initializer;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.*;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetClassOrObject;
|
||||
import org.jetbrains.jet.lang.psi.JetDelegationSpecifier;
|
||||
import org.jetbrains.jet.lang.psi.JetDelegatorToSuperCall;
|
||||
import org.jetbrains.jet.lang.psi.JetParameter;
|
||||
import org.jetbrains.k2js.translate.context.Namer;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.utils.PsiUtils;
|
||||
import org.jetbrains.k2js.translate.utils.TranslationUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.*;
|
||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.assignmentToBackingField;
|
||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.functionWithScope;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class ClassInitializerTranslator extends AbstractInitializerTranslator {
|
||||
|
||||
@NotNull
|
||||
private final JetClassOrObject classDeclaration;
|
||||
@NotNull
|
||||
private final List<JsStatement> initializerStatements = new ArrayList<JsStatement>();
|
||||
|
||||
public ClassInitializerTranslator(@NotNull JetClassOrObject classDeclaration, @NotNull TranslationContext context) {
|
||||
super(context.getScopeForElement(classDeclaration).innerScope
|
||||
("initializer " + classDeclaration.getName()), context);
|
||||
this.classDeclaration = classDeclaration;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected JsFunction generateInitializerFunction() {
|
||||
JsFunction result = functionWithScope(initializerMethodScope);
|
||||
//NOTE: that while we translateAsLocalNameReference constructor parameters we also add property initializer statements
|
||||
// for properties declared as constructor parameters
|
||||
result.setParameters(translatePrimaryConstructorParameters());
|
||||
mayBeAddCallToSuperMethod();
|
||||
result.setBody(generateInitializerMethodBody());
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsBlock generateInitializerMethodBody() {
|
||||
initializerStatements.addAll(translateClassInitializers(classDeclaration));
|
||||
return AstUtil.newBlock(initializerStatements);
|
||||
}
|
||||
|
||||
private void mayBeAddCallToSuperMethod() {
|
||||
if (hasAncestorClass(bindingContext(), classDeclaration)) {
|
||||
JetDelegatorToSuperCall superCall = getSuperCall();
|
||||
if (superCall == null) return;
|
||||
addCallToSuperMethod(superCall);
|
||||
}
|
||||
}
|
||||
|
||||
private void addCallToSuperMethod(@NotNull JetDelegatorToSuperCall superCall) {
|
||||
//TODO: look into
|
||||
JsName superMethodName = initializerMethodScope.jsScope().declareName(Namer.superMethodName());
|
||||
List<JsExpression> arguments = translateArguments(superCall);
|
||||
initializerStatements.add(AstUtil.convertToStatement
|
||||
(AstUtil.newInvocation(AstUtil.thisQualifiedReference(superMethodName), arguments)));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<JsExpression> translateArguments(@NotNull JetDelegatorToSuperCall superCall) {
|
||||
//TODO: use the same mechanism as in call translator
|
||||
return TranslationUtils.translateArgumentList(context(), superCall.getValueArguments());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private JetDelegatorToSuperCall getSuperCall() {
|
||||
JetDelegatorToSuperCall result = null;
|
||||
for (JetDelegationSpecifier specifier : classDeclaration.getDelegationSpecifiers()) {
|
||||
if (specifier instanceof JetDelegatorToSuperCall) {
|
||||
result = (JetDelegatorToSuperCall) specifier;
|
||||
}
|
||||
}
|
||||
//assert result != null : "Class must call ancestor's constructor.";
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
List<JsParameter> translatePrimaryConstructorParameters() {
|
||||
List<JetParameter> parameterList = PsiUtils.getPrimaryConstructorParameters(classDeclaration);
|
||||
List<JsParameter> result = new ArrayList<JsParameter>();
|
||||
for (JetParameter jetParameter : parameterList) {
|
||||
result.add(translateParameter(jetParameter));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsParameter translateParameter(@NotNull JetParameter jetParameter) {
|
||||
DeclarationDescriptor parameterDescriptor =
|
||||
getDescriptorForElement(bindingContext(), jetParameter);
|
||||
JsName parameterName = context().getNameForDescriptor(parameterDescriptor);
|
||||
JsParameter jsParameter = new JsParameter(parameterName);
|
||||
mayBeAddInitializerStatementForProperty(jsParameter, jetParameter);
|
||||
return jsParameter;
|
||||
}
|
||||
|
||||
private void mayBeAddInitializerStatementForProperty(@NotNull JsParameter jsParameter,
|
||||
@NotNull JetParameter jetParameter) {
|
||||
PropertyDescriptor propertyDescriptor =
|
||||
getPropertyDescriptorForConstructorParameter(bindingContext(), jetParameter);
|
||||
if (propertyDescriptor != null) {
|
||||
JsStatement assignmentToBackingFieldExpression = assignmentToBackingField
|
||||
(context(), propertyDescriptor, jsParameter.getName().makeRef());
|
||||
initializerStatements.add(assignmentToBackingFieldExpression);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.initializer;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.backend.js.ast.JsInvocation;
|
||||
import com.google.dart.compiler.backend.js.ast.JsName;
|
||||
import com.google.dart.compiler.backend.js.ast.JsStatement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.declaration.ClassTranslator;
|
||||
import org.jetbrains.k2js.translate.general.Translation;
|
||||
import org.jetbrains.k2js.translate.general.TranslatorVisitor;
|
||||
import org.jetbrains.k2js.translate.utils.BindingUtils;
|
||||
import org.jetbrains.k2js.translate.utils.TranslationUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getDeclarationsForNamespace;
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getPropertyDescriptorForObjectDeclaration;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getObjectDeclarationForName;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class InitializerVisitor extends TranslatorVisitor<List<JsStatement>> {
|
||||
|
||||
/*package*/ InitializerVisitor() {
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<JsStatement> visitProperty(@NotNull JetProperty expression, @NotNull TranslationContext context) {
|
||||
JetExpression initializer = expression.getInitializer();
|
||||
if (initializer == null) {
|
||||
return new ArrayList<JsStatement>();
|
||||
}
|
||||
return Arrays.asList(translateInitializer(expression, context, initializer));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsStatement translateInitializer(@NotNull JetProperty property, @NotNull TranslationContext context,
|
||||
@NotNull JetExpression initializer) {
|
||||
JsExpression initExpression = Translation.translateAsExpression(initializer, context);
|
||||
return assignmentToBackingField(property, initExpression, context);
|
||||
}
|
||||
|
||||
//TODO:
|
||||
@NotNull
|
||||
JsStatement assignmentToBackingField(@NotNull JetProperty property, @NotNull JsExpression initExpression,
|
||||
@NotNull TranslationContext context) {
|
||||
|
||||
PropertyDescriptor propertyDescriptor = BindingUtils.getPropertyDescriptor(context.bindingContext(), property);
|
||||
return TranslationUtils.assignmentToBackingField(context, propertyDescriptor, initExpression);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<JsStatement> visitAnonymousInitializer(@NotNull JetClassInitializer initializer,
|
||||
@NotNull TranslationContext context) {
|
||||
return Arrays.asList(Translation.translateAsStatement(initializer.getBody(), context));
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
// Not interested in other types of declarations, they do not contain initializers.
|
||||
public List<JsStatement> visitDeclaration(@NotNull JetDeclaration expression, @NotNull TranslationContext context) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<JsStatement> visitObjectDeclarationName(@NotNull JetObjectDeclarationName objectName,
|
||||
@NotNull TranslationContext context) {
|
||||
PropertyDescriptor propertyDescriptorForObjectDeclaration
|
||||
= getPropertyDescriptorForObjectDeclaration(context.bindingContext(), objectName);
|
||||
JsName objectPropertyName = context.getNameForDescriptor(propertyDescriptorForObjectDeclaration);
|
||||
JetObjectDeclaration objectDeclaration = getObjectDeclarationForName(objectName);
|
||||
JsInvocation objectValue = ClassTranslator.generateClassCreationExpression(objectDeclaration, context);
|
||||
return singletonList(TranslationUtils.assignmentToBackingField(context,
|
||||
propertyDescriptorForObjectDeclaration, objectValue));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<JsStatement> traverseClass(@NotNull JetClassOrObject expression, @NotNull TranslationContext context) {
|
||||
List<JsStatement> initializerStatements = new ArrayList<JsStatement>();
|
||||
for (JetDeclaration declaration : expression.getDeclarations()) {
|
||||
initializerStatements.addAll(declaration.accept(this, context));
|
||||
}
|
||||
return initializerStatements;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<JsStatement> traverseNamespace(@NotNull NamespaceDescriptor namespace, @NotNull TranslationContext context) {
|
||||
List<JsStatement> initializerStatements = new ArrayList<JsStatement>();
|
||||
for (JetDeclaration declaration : getDeclarationsForNamespace(context.bindingContext(), namespace)) {
|
||||
initializerStatements.addAll(declaration.accept(this, context));
|
||||
}
|
||||
return initializerStatements;
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.initializer;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsFunction;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.functionWithScope;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class NamespaceInitializerTranslator extends AbstractInitializerTranslator {
|
||||
|
||||
@NotNull
|
||||
private final NamespaceDescriptor namespace;
|
||||
|
||||
public NamespaceInitializerTranslator(@NotNull NamespaceDescriptor namespace, @NotNull TranslationContext context) {
|
||||
super(context.getScopeForDescriptor(namespace).innerScope
|
||||
("initializer " + namespace.getName()), context);
|
||||
this.namespace = namespace;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected JsFunction generateInitializerFunction() {
|
||||
JsFunction result = functionWithScope(initializerMethodScope);
|
||||
result.setBody(AstUtil.newBlock(translateNamespaceInitializers(namespace)));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.intrinsic;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
|
||||
import org.jetbrains.jet.lexer.JetToken;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public abstract class CompareToIntrinsic implements Intrinsic {
|
||||
|
||||
private JetToken comparisonToken = null;
|
||||
|
||||
@NotNull
|
||||
protected JetToken getComparisonToken() {
|
||||
assert comparisonToken != null : "Should use set token first";
|
||||
return comparisonToken;
|
||||
}
|
||||
|
||||
public void setComparisonToken(@NotNull JetToken comparisonToken) {
|
||||
assert OperatorConventions.COMPARISON_OPERATIONS.contains(comparisonToken)
|
||||
: "Should be a comparison operation";
|
||||
this.comparisonToken = comparisonToken;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.intrinsic;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public abstract class EqualsIntrinsic implements Intrinsic {
|
||||
|
||||
@NotNull
|
||||
private Boolean isNegated = false;
|
||||
|
||||
public void setNegated(boolean isNegated) {
|
||||
this.isNegated = isNegated;
|
||||
}
|
||||
|
||||
protected boolean isNegated() {
|
||||
return isNegated;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.intrinsic;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public interface FunctionIntrinsic extends Intrinsic {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.intrinsic;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
* <p/>
|
||||
* Base class for all intrinsics.
|
||||
*/
|
||||
public interface Intrinsic {
|
||||
|
||||
@NotNull
|
||||
JsExpression apply(@Nullable JsExpression receiver, @NotNull List<JsExpression> arguments,
|
||||
@NotNull TranslationContext context);
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.intrinsic;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.types.JetStandardClasses;
|
||||
import org.jetbrains.jet.lang.types.JetStandardLibrary;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.PrimitiveType;
|
||||
import org.jetbrains.jet.lexer.JetToken;
|
||||
import org.jetbrains.k2js.translate.intrinsic.array.*;
|
||||
import org.jetbrains.k2js.translate.intrinsic.primitive.*;
|
||||
import org.jetbrains.k2js.translate.intrinsic.string.CharAtIntrinsic;
|
||||
import org.jetbrains.k2js.translate.intrinsic.string.LengthIntrinsic;
|
||||
import org.jetbrains.k2js.translate.intrinsic.tuple.TupleAccessIntrinsic;
|
||||
import org.jetbrains.k2js.translate.operation.OperatorTable;
|
||||
import org.jetbrains.k2js.translate.utils.DescriptorUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.jetbrains.jet.lang.types.expressions.OperatorConventions.*;
|
||||
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.getFunctionByName;
|
||||
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.getPropertyByName;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
* <p/>
|
||||
* Provides mechanism to substitute method calls /w native constucts directly.
|
||||
*/
|
||||
public final class Intrinsics {
|
||||
|
||||
@NotNull
|
||||
private final Map<FunctionDescriptor, FunctionIntrinsic> functionIntrinsics =
|
||||
new HashMap<FunctionDescriptor, FunctionIntrinsic>();
|
||||
|
||||
@NotNull
|
||||
private final Map<FunctionDescriptor, EqualsIntrinsic> equalsIntrinsics =
|
||||
new HashMap<FunctionDescriptor, EqualsIntrinsic>();
|
||||
|
||||
@NotNull
|
||||
private final Map<FunctionDescriptor, CompareToIntrinsic> compareToIntrinsics =
|
||||
new HashMap<FunctionDescriptor, CompareToIntrinsic>();
|
||||
|
||||
public static Intrinsics standardLibraryIntrinsics(@NotNull JetStandardLibrary library) {
|
||||
return new Intrinsics(library);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final JetStandardLibrary library;
|
||||
|
||||
private Intrinsics(@NotNull JetStandardLibrary library) {
|
||||
this.library = library;
|
||||
declareOperatorIntrinsics();
|
||||
declareStringIntrinsics();
|
||||
declareTuplesIntrinsics();
|
||||
declareArrayIntrinsics();
|
||||
}
|
||||
|
||||
private void declareTuplesIntrinsics() {
|
||||
for (int tupleSize = 0; tupleSize < JetStandardClasses.TUPLE_COUNT; ++tupleSize) {
|
||||
declareTupleIntrinsics(tupleSize);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: provide generic mechanism or refactor
|
||||
private void declareArrayIntrinsics() {
|
||||
|
||||
List<JetType> arrayTypes = getLibraryArrayTypes();
|
||||
|
||||
for (JetType arrayType : arrayTypes) {
|
||||
declareIntrinsicsForArrayType(arrayType);
|
||||
}
|
||||
declareNullConstructorIntrinsic();
|
||||
}
|
||||
|
||||
private void declareNullConstructorIntrinsic() {
|
||||
//TODO:
|
||||
FunctionDescriptor nullArrayConstructor = library.getLibraryScope().getFunctions("Array").iterator().next();
|
||||
functionIntrinsics.put(nullArrayConstructor, ArrayNullConstructorIntrinsic.INSTANCE);
|
||||
}
|
||||
|
||||
//TODO: some dangerous operation unchecked here
|
||||
private void declareIntrinsicsForArrayType(@NotNull JetType arrayType) {
|
||||
JetScope arrayMemberScope = arrayType.getMemberScope();
|
||||
FunctionDescriptor setFunction = getFunctionByName(arrayMemberScope, "set");
|
||||
functionIntrinsics.put(setFunction, ArraySetIntrinsic.INSTANCE);
|
||||
FunctionDescriptor getFunction = getFunctionByName(arrayMemberScope, "get");
|
||||
functionIntrinsics.put(getFunction, ArrayGetIntrinsic.INSTANCE);
|
||||
PropertyDescriptor sizeProperty = getPropertyByName(arrayMemberScope, "size");
|
||||
functionIntrinsics.put(sizeProperty.getGetter(), ArraySizeIntrinsic.INSTANCE);
|
||||
PropertyDescriptor indicesProperty = getPropertyByName(arrayMemberScope, "indices");
|
||||
functionIntrinsics.put(indicesProperty.getGetter(), ArrayIndicesIntrinsic.INSTANCE);
|
||||
FunctionDescriptor iteratorFunction = getFunctionByName(arrayMemberScope, "iterator");
|
||||
functionIntrinsics.put(iteratorFunction, ArrayIteratorIntrinsic.INSTANCE);
|
||||
ConstructorDescriptor arrayConstructor =
|
||||
((ClassDescriptor) arrayMemberScope.getContainingDeclaration()).getConstructors().iterator().next();
|
||||
functionIntrinsics.put(arrayConstructor, ArrayFunctionConstructorIntrinsic.INSTANCE);
|
||||
}
|
||||
|
||||
private List<JetType> getLibraryArrayTypes() {
|
||||
List<JetType> arrayTypes = Lists.newArrayList();
|
||||
for (PrimitiveType type : PrimitiveType.values()) {
|
||||
arrayTypes.add(library.getPrimitiveArrayJetType(type));
|
||||
}
|
||||
arrayTypes.add(library.getArray().getDefaultType());
|
||||
return arrayTypes;
|
||||
}
|
||||
|
||||
private void declareTupleIntrinsics(int tupleSize) {
|
||||
JetScope libraryScope = library.getLibraryScope();
|
||||
assert libraryScope != null;
|
||||
ClassifierDescriptor tupleDescriptor = libraryScope.getClassifier("Tuple" + tupleSize);
|
||||
assert tupleDescriptor != null;
|
||||
declareTupleIntrinsicAccessors(tupleDescriptor, tupleSize);
|
||||
}
|
||||
|
||||
private void declareStringIntrinsics() {
|
||||
PropertyDescriptor lengthProperty =
|
||||
getPropertyByName(library.getCharSequence().getDefaultType().getMemberScope(), "length");
|
||||
functionIntrinsics.put(lengthProperty.getGetter(), LengthIntrinsic.INSTANCE);
|
||||
FunctionDescriptor getFunction =
|
||||
getFunctionByName(library.getString().getDefaultType().getMemberScope(), "get");
|
||||
functionIntrinsics.put(getFunction, CharAtIntrinsic.INSTANCE);
|
||||
}
|
||||
|
||||
private void declareTupleIntrinsicAccessors(@NotNull ClassifierDescriptor tupleDescriptor,
|
||||
int tupleSize) {
|
||||
for (int elementIndex = 0; elementIndex < tupleSize; ++elementIndex) {
|
||||
String accessorName = "_" + (elementIndex + 1);
|
||||
PropertyDescriptor propertyDescriptor =
|
||||
getPropertyByName(tupleDescriptor.getDefaultType().getMemberScope(), accessorName);
|
||||
functionIntrinsics.put(propertyDescriptor.getGetter(), new TupleAccessIntrinsic(elementIndex));
|
||||
}
|
||||
}
|
||||
|
||||
private void declareOperatorIntrinsics() {
|
||||
IntrinsicDeclarationVisitor visitor = new IntrinsicDeclarationVisitor();
|
||||
for (DeclarationDescriptor descriptor : library.getLibraryScope().getAllDescriptors()) {
|
||||
//noinspection NullableProblems
|
||||
descriptor.accept(visitor, null);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isIntrinsic(@NotNull DeclarationDescriptor descriptor) {
|
||||
//NOTE: that if we want to add other intrinsics we have to modify this method
|
||||
if (descriptor instanceof FunctionDescriptor) {
|
||||
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor.getOriginal();
|
||||
return (equalsIntrinsics.containsKey(functionDescriptor) ||
|
||||
compareToIntrinsics.containsKey(functionDescriptor) ||
|
||||
functionIntrinsics.containsKey(functionDescriptor));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FunctionIntrinsic getFunctionIntrinsic(@NotNull FunctionDescriptor descriptor) {
|
||||
return functionIntrinsics.get(descriptor.getOriginal());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public CompareToIntrinsic getCompareToIntrinsic(@NotNull FunctionDescriptor descriptor) {
|
||||
return compareToIntrinsics.get(descriptor.getOriginal());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public EqualsIntrinsic getEqualsIntrinsic(@NotNull FunctionDescriptor descriptor) {
|
||||
return equalsIntrinsics.get(descriptor.getOriginal());
|
||||
}
|
||||
|
||||
private final class IntrinsicDeclarationVisitor extends DeclarationDescriptorVisitor<Void, Void> {
|
||||
|
||||
@Override
|
||||
public Void visitClassDescriptor(@NotNull ClassDescriptor descriptor, @Nullable Void nothing) {
|
||||
for (DeclarationDescriptor memberDescriptor :
|
||||
descriptor.getDefaultType().getMemberScope().getAllDescriptors()) {
|
||||
//noinspection NullableProblems
|
||||
memberDescriptor.accept(this, null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitFunctionDescriptor(@NotNull FunctionDescriptor descriptor, @Nullable Void nothing) {
|
||||
if (!isIntrinsic(descriptor)) {
|
||||
declareOperatorIntrinsic(descriptor);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/*package*/ void declareOperatorIntrinsic(@NotNull FunctionDescriptor descriptor) {
|
||||
tryResolveAsEqualsCompareToOrRangeToIntrinsic(descriptor);
|
||||
tryResolveAsUnaryIntrinsics(descriptor);
|
||||
tryResolveAsBinaryIntrinsics(descriptor);
|
||||
}
|
||||
|
||||
private void tryResolveAsEqualsCompareToOrRangeToIntrinsic(@NotNull FunctionDescriptor descriptor) {
|
||||
String functionName = descriptor.getName();
|
||||
if (functionName.equals(COMPARE_TO)) {
|
||||
compareToIntrinsics.put(descriptor, PrimitiveCompareToIntrinsic.newInstance());
|
||||
}
|
||||
if (functionName.equals(EQUALS)) {
|
||||
equalsIntrinsics.put(descriptor, PrimitiveEqualsIntrinsic.newInstance());
|
||||
}
|
||||
if (functionName.equals("rangeTo")) {
|
||||
functionIntrinsics.put(descriptor, PrimitiveRangeToIntrinsic.newInstance());
|
||||
}
|
||||
}
|
||||
|
||||
private void tryResolveAsUnaryIntrinsics(@NotNull FunctionDescriptor descriptor) {
|
||||
String functionName = descriptor.getName();
|
||||
JetToken token = UNARY_OPERATION_NAMES.inverse().get(functionName);
|
||||
|
||||
if (token == null) return;
|
||||
if (!isUnaryOperation(descriptor)) return;
|
||||
|
||||
functionIntrinsics.put(descriptor, PrimitiveUnaryOperationIntrinsic.newInstance(token));
|
||||
}
|
||||
|
||||
private void tryResolveAsBinaryIntrinsics(@NotNull FunctionDescriptor descriptor) {
|
||||
String functionName = descriptor.getName();
|
||||
|
||||
if (isUnaryOperation(descriptor)) return;
|
||||
|
||||
JetToken token = BINARY_OPERATION_NAMES.inverse().get(functionName);
|
||||
if (token == null) return;
|
||||
|
||||
if (!OperatorTable.hasCorrespondingBinaryOperator(token)) return;
|
||||
functionIntrinsics.put(descriptor, PrimitiveBinaryOperationIntrinsic.newInstance(token));
|
||||
}
|
||||
|
||||
private boolean isUnaryOperation(@NotNull FunctionDescriptor descriptor) {
|
||||
return !DescriptorUtils.hasParameters(descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.intrinsic.array;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.backend.js.ast.JsNameRef;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.intrinsic.FunctionIntrinsic;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public enum ArrayFunctionConstructorIntrinsic implements FunctionIntrinsic {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression apply(@Nullable JsExpression receiver,
|
||||
@NotNull List<JsExpression> arguments,
|
||||
@NotNull TranslationContext context) {
|
||||
assert receiver == null;
|
||||
assert arguments.size() == 2;
|
||||
//TODO: provide better mechanism
|
||||
JsNameRef iteratorFunName = AstUtil.newQualifiedNameRef("Kotlin.arrayFromFun");
|
||||
return AstUtil.newInvocation(iteratorFunName, arguments);
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.intrinsic.array;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsArrayAccess;
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.intrinsic.FunctionIntrinsic;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public enum ArrayGetIntrinsic implements FunctionIntrinsic {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression apply(@Nullable JsExpression receiver, @NotNull List<JsExpression> arguments,
|
||||
@NotNull TranslationContext context) {
|
||||
assert receiver != null;
|
||||
assert arguments.size() == 1 : "Array get expression must have one argument.";
|
||||
JsExpression indexExpression = arguments.get(0);
|
||||
return new JsArrayAccess(receiver, indexExpression);
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.intrinsic.array;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.backend.js.ast.JsNameRef;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.intrinsic.FunctionIntrinsic;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public enum ArrayIndicesIntrinsic implements FunctionIntrinsic {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression apply(@Nullable JsExpression receiver, @NotNull List<JsExpression> arguments,
|
||||
@NotNull TranslationContext context) {
|
||||
assert receiver != null;
|
||||
assert arguments.size() == 0;
|
||||
//TODO: provide better mechanism
|
||||
JsNameRef iteratorFunName = AstUtil.newQualifiedNameRef("Kotlin.arrayIndices");
|
||||
return AstUtil.newInvocation(iteratorFunName, receiver);
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.intrinsic.array;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.backend.js.ast.JsNameRef;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.intrinsic.FunctionIntrinsic;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public enum ArrayIteratorIntrinsic implements FunctionIntrinsic {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression apply(@Nullable JsExpression receiver, @NotNull List<JsExpression> arguments,
|
||||
@NotNull TranslationContext context) {
|
||||
assert receiver != null;
|
||||
assert arguments.size() == 0;
|
||||
//TODO: provide better mechanism
|
||||
JsNameRef iteratorFunName = AstUtil.newQualifiedNameRef("Kotlin.arrayIterator");
|
||||
return AstUtil.newInvocation(iteratorFunName, receiver);
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.intrinsic.array;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.backend.js.ast.JsNameRef;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.intrinsic.FunctionIntrinsic;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public enum ArrayNullConstructorIntrinsic implements FunctionIntrinsic {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
//TODO: implement function passing to array constructor
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression apply(@Nullable JsExpression receiver, @NotNull List<JsExpression> arguments,
|
||||
@NotNull TranslationContext context) {
|
||||
assert receiver == null;
|
||||
assert arguments.size() == 1;
|
||||
//TODO: provide better mechanism
|
||||
JsNameRef nullArrayFunName = AstUtil.newQualifiedNameRef("Kotlin.nullArray");
|
||||
return AstUtil.newInvocation(nullArrayFunName, arguments);
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.intrinsic.array;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsArrayAccess;
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.intrinsic.FunctionIntrinsic;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public enum ArraySetIntrinsic implements FunctionIntrinsic {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression apply(@Nullable JsExpression receiver, @NotNull List<JsExpression> arguments,
|
||||
@NotNull TranslationContext context) {
|
||||
assert receiver != null;
|
||||
assert arguments.size() == 2 : "Array set expression must have two arguments.";
|
||||
JsExpression indexExpression = arguments.get(0);
|
||||
JsExpression value = arguments.get(1);
|
||||
JsArrayAccess arrayAccess = AstUtil.newArrayAccess(receiver, indexExpression);
|
||||
return AstUtil.newAssignment(arrayAccess, value);
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.intrinsic.array;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.backend.js.ast.JsNameRef;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.intrinsic.FunctionIntrinsic;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public enum ArraySizeIntrinsic implements FunctionIntrinsic {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression apply(@Nullable JsExpression receiver, @NotNull List<JsExpression> arguments,
|
||||
@NotNull TranslationContext context) {
|
||||
assert receiver != null;
|
||||
assert arguments.isEmpty() : "Length expression must have zero arguments.";
|
||||
//TODO: provide better way
|
||||
JsNameRef lengthProperty = AstUtil.newQualifiedNameRef("length");
|
||||
AstUtil.setQualifier(lengthProperty, receiver);
|
||||
return lengthProperty;
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.intrinsic.primitive;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsBinaryOperation;
|
||||
import com.google.dart.compiler.backend.js.ast.JsBinaryOperator;
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lexer.JetToken;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.intrinsic.FunctionIntrinsic;
|
||||
import org.jetbrains.k2js.translate.operation.OperatorTable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class PrimitiveBinaryOperationIntrinsic implements FunctionIntrinsic {
|
||||
|
||||
@NotNull
|
||||
public static PrimitiveBinaryOperationIntrinsic newInstance(@NotNull JetToken token) {
|
||||
JsBinaryOperator operator = OperatorTable.getBinaryOperator(token);
|
||||
return new PrimitiveBinaryOperationIntrinsic(operator);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final JsBinaryOperator operator;
|
||||
|
||||
private PrimitiveBinaryOperationIntrinsic(@NotNull JsBinaryOperator operator) {
|
||||
this.operator = operator;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression apply(@Nullable JsExpression receiver, @NotNull List<JsExpression> arguments,
|
||||
@NotNull TranslationContext context) {
|
||||
assert arguments.size() == 1 : "Binary operator should have a receiver and one argument";
|
||||
return new JsBinaryOperation(operator, receiver, arguments.get(0));
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.intrinsic.primitive;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsBinaryOperation;
|
||||
import com.google.dart.compiler.backend.js.ast.JsBinaryOperator;
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.intrinsic.CompareToIntrinsic;
|
||||
import org.jetbrains.k2js.translate.operation.OperatorTable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class PrimitiveCompareToIntrinsic extends CompareToIntrinsic {
|
||||
|
||||
@NotNull
|
||||
public static PrimitiveCompareToIntrinsic newInstance() {
|
||||
return new PrimitiveCompareToIntrinsic();
|
||||
}
|
||||
|
||||
private PrimitiveCompareToIntrinsic() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsExpression apply(@Nullable JsExpression receiver, @NotNull List<JsExpression> arguments,
|
||||
@NotNull TranslationContext context) {
|
||||
assert arguments.size() == 1 : "Equals operation should have one argument";
|
||||
JsBinaryOperator operator = OperatorTable.getBinaryOperator(getComparisonToken());
|
||||
JsExpression argument = arguments.get(0);
|
||||
return new JsBinaryOperation(operator, receiver, argument);
|
||||
}
|
||||
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.intrinsic.primitive;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.intrinsic.EqualsIntrinsic;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class PrimitiveEqualsIntrinsic extends EqualsIntrinsic {
|
||||
|
||||
@NotNull
|
||||
public static PrimitiveEqualsIntrinsic newInstance() {
|
||||
return new PrimitiveEqualsIntrinsic();
|
||||
}
|
||||
|
||||
private PrimitiveEqualsIntrinsic() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsExpression apply(@Nullable JsExpression receiver, @NotNull List<JsExpression> arguments,
|
||||
@NotNull TranslationContext context) {
|
||||
assert arguments.size() == 1 : "Equals operation should have one argument";
|
||||
if (isNegated()) {
|
||||
return AstUtil.notEqual(receiver, arguments.get(0));
|
||||
} else {
|
||||
return AstUtil.equals(receiver, arguments.get(0));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.intrinsic.primitive;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsBinaryOperation;
|
||||
import com.google.dart.compiler.backend.js.ast.JsBooleanLiteral;
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.backend.js.ast.JsNew;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.intrinsic.FunctionIntrinsic;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class PrimitiveRangeToIntrinsic implements FunctionIntrinsic {
|
||||
|
||||
@NotNull
|
||||
public static PrimitiveRangeToIntrinsic newInstance() {
|
||||
return new PrimitiveRangeToIntrinsic();
|
||||
}
|
||||
|
||||
private PrimitiveRangeToIntrinsic() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression apply(@Nullable JsExpression rangeStart, @NotNull List<JsExpression> arguments,
|
||||
@NotNull TranslationContext context) {
|
||||
assert arguments.size() == 1 : "RangeTo must have one argument.";
|
||||
JsExpression rangeEnd = arguments.get(0);
|
||||
JsBinaryOperation rangeSize = AstUtil.sum(AstUtil.subtract(rangeEnd, rangeStart),
|
||||
context.program().getNumberLiteral(1));
|
||||
//TODO: provide a way not to hard code this value
|
||||
JsNew numberRangeConstructorInvocation
|
||||
= new JsNew(AstUtil.newQualifiedNameRef("Kotlin.NumberRange"));
|
||||
//TODO: add tests and correct expression for reversed ranges.
|
||||
JsBooleanLiteral isRangeReversed = context.program().getFalseLiteral();
|
||||
numberRangeConstructorInvocation.setArguments(Arrays.asList(rangeStart, rangeSize, isRangeReversed));
|
||||
return numberRangeConstructorInvocation;
|
||||
}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.intrinsic.primitive;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.backend.js.ast.JsPrefixOperation;
|
||||
import com.google.dart.compiler.backend.js.ast.JsUnaryOperator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lexer.JetToken;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.intrinsic.FunctionIntrinsic;
|
||||
import org.jetbrains.k2js.translate.operation.OperatorTable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class PrimitiveUnaryOperationIntrinsic implements FunctionIntrinsic {
|
||||
|
||||
@NotNull
|
||||
public static PrimitiveUnaryOperationIntrinsic newInstance(@NotNull JetToken token) {
|
||||
JsUnaryOperator operator = OperatorTable.getUnaryOperator(token);
|
||||
return new PrimitiveUnaryOperationIntrinsic(operator);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final JsUnaryOperator operator;
|
||||
|
||||
private PrimitiveUnaryOperationIntrinsic(@NotNull JsUnaryOperator operator) {
|
||||
this.operator = operator;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression apply(@Nullable JsExpression receiver, @NotNull List<JsExpression> arguments,
|
||||
@NotNull TranslationContext context) {
|
||||
assert receiver != null;
|
||||
assert arguments.size() == 0 : "Unary operator should not have arguments.";
|
||||
//NOTE: cannot use this for increment/decrement
|
||||
return new JsPrefixOperation(operator, receiver);
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.intrinsic.string;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.backend.js.ast.JsNameRef;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.intrinsic.FunctionIntrinsic;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public enum CharAtIntrinsic implements FunctionIntrinsic {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression apply(@Nullable JsExpression receiver, @NotNull List<JsExpression> arguments,
|
||||
@NotNull TranslationContext context) {
|
||||
assert receiver != null;
|
||||
assert arguments.size() == 1 : "get Char expression must have 1 arguments.";
|
||||
//TODO: provide better way
|
||||
JsNameRef charAtReference = AstUtil.newQualifiedNameRef("charAt");
|
||||
AstUtil.setQualifier(charAtReference, receiver);
|
||||
return AstUtil.newInvocation(charAtReference, arguments);
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.intrinsic.string;
|
||||
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.backend.js.ast.JsNameRef;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.intrinsic.FunctionIntrinsic;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public enum LengthIntrinsic implements FunctionIntrinsic {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression apply(@Nullable JsExpression receiver, @NotNull List<JsExpression> arguments,
|
||||
@NotNull TranslationContext context) {
|
||||
assert receiver != null;
|
||||
assert arguments.isEmpty() : "Length expression must have zero arguments.";
|
||||
//TODO: provide better way
|
||||
JsNameRef lengthProperty = AstUtil.newQualifiedNameRef("length");
|
||||
AstUtil.setQualifier(lengthProperty, receiver);
|
||||
return lengthProperty;
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.intrinsic.tuple;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.intrinsic.FunctionIntrinsic;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class TupleAccessIntrinsic implements FunctionIntrinsic {
|
||||
|
||||
private final int elementIndex;
|
||||
|
||||
public TupleAccessIntrinsic(int elementIndex) {
|
||||
this.elementIndex = elementIndex;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression apply(@Nullable JsExpression receiver, @NotNull List<JsExpression> arguments,
|
||||
@NotNull TranslationContext context) {
|
||||
assert arguments.isEmpty() : "Tuple access expression should not have any arguments.";
|
||||
return AstUtil.newArrayAccess(receiver, context.program().getNumberLiteral(elementIndex));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.operation;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetBinaryExpression;
|
||||
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
|
||||
import org.jetbrains.jet.lexer.JetToken;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
import org.jetbrains.k2js.translate.reference.AccessTranslator;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.isVariableReassignment;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.isAssignment;
|
||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.isIntrinsicOperation;
|
||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateRightExpression;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public abstract class AssignmentTranslator extends AbstractTranslator {
|
||||
|
||||
public static boolean isAssignmentOperator(JetBinaryExpression expression) {
|
||||
JetToken operationToken = getOperationToken(expression);
|
||||
return (OperatorConventions.ASSIGNMENT_OPERATIONS.keySet().contains(operationToken)
|
||||
|| isAssignment(operationToken));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression translate(@NotNull JetBinaryExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
if (isIntrinsicOperation(context, expression)) {
|
||||
return IntrinsicAssignmentTranslator.translate(expression, context);
|
||||
}
|
||||
return OverloadedAssignmentTranslator.translate(expression, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected final JetBinaryExpression expression;
|
||||
protected final AccessTranslator accessTranslator;
|
||||
protected final boolean isVariableReassignment;
|
||||
@NotNull
|
||||
protected final JsExpression right;
|
||||
|
||||
protected AssignmentTranslator(@NotNull JetBinaryExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
super(context);
|
||||
this.expression = expression;
|
||||
this.isVariableReassignment = isVariableReassignment(context.bindingContext(), expression);
|
||||
this.accessTranslator = AccessTranslator.getAccessTranslator(expression.getLeft(), context());
|
||||
this.right = translateRightExpression(context(), expression);
|
||||
}
|
||||
}
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.operation;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsBinaryOperation;
|
||||
import com.google.dart.compiler.backend.js.ast.JsBinaryOperator;
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetBinaryExpression;
|
||||
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
|
||||
import org.jetbrains.jet.lexer.JetToken;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
import org.jetbrains.k2js.translate.intrinsic.EqualsIntrinsic;
|
||||
import org.jetbrains.k2js.translate.reference.CallBuilder;
|
||||
import org.jetbrains.k2js.translate.reference.CallType;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static com.google.dart.compiler.util.AstUtil.not;
|
||||
import static org.jetbrains.k2js.translate.operation.AssignmentTranslator.isAssignmentOperator;
|
||||
import static org.jetbrains.k2js.translate.operation.CompareToTranslator.isCompareToCall;
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptorForOperationExpression;
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getResolvedCall;
|
||||
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.isEquals;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.*;
|
||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateLeftExpression;
|
||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.translateRightExpression;
|
||||
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class BinaryOperationTranslator extends AbstractTranslator {
|
||||
|
||||
@NotNull
|
||||
public static JsExpression translate(@NotNull JetBinaryExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return (new BinaryOperationTranslator(expression, context).translate());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
/*package*/ static JsExpression translateAsOverloadedCall(@NotNull JetBinaryExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return (new BinaryOperationTranslator(expression, context)).translateAsOverloadedBinaryOperation();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final JetBinaryExpression expression;
|
||||
|
||||
@Nullable
|
||||
private final FunctionDescriptor operationDescriptor;
|
||||
|
||||
private BinaryOperationTranslator(@NotNull JetBinaryExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
super(context);
|
||||
this.expression = expression;
|
||||
this.operationDescriptor =
|
||||
getFunctionDescriptorForOperationExpression(bindingContext(), expression);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression translate() {
|
||||
if (isAssignmentOperator(expression)) {
|
||||
return AssignmentTranslator.translate(expression, context());
|
||||
}
|
||||
if (isNotOverloadable()) {
|
||||
return translateAsUnOverloadableBinaryOperation();
|
||||
}
|
||||
if (isCompareToCall(expression, context())) {
|
||||
return CompareToTranslator.translate(expression, context());
|
||||
}
|
||||
assert operationDescriptor != null :
|
||||
"Overloadable operations must have not null descriptor";
|
||||
if (isEquals(operationDescriptor)) {
|
||||
return translateAsEqualsCall();
|
||||
}
|
||||
return translateAsOverloadedBinaryOperation();
|
||||
}
|
||||
|
||||
private boolean isNotOverloadable() {
|
||||
return operationDescriptor == null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression translateAsEqualsCall() {
|
||||
assert operationDescriptor != null : "Equals operation must resolve to descriptor.";
|
||||
EqualsIntrinsic intrinsic = context().intrinsics().getEqualsIntrinsic(operationDescriptor);
|
||||
intrinsic.setNegated(expression.getOperationToken().equals(JetTokens.EXCLEQ));
|
||||
JsExpression left = translateLeftExpression(context(), expression);
|
||||
JsExpression right = translateRightExpression(context(), expression);
|
||||
return intrinsic.apply(left, Arrays.asList(right), context());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression translateAsUnOverloadableBinaryOperation() {
|
||||
JetToken token = getOperationToken(expression);
|
||||
JsBinaryOperator operator = OperatorTable.getBinaryOperator(token);
|
||||
assert OperatorConventions.NOT_OVERLOADABLE.contains(token);
|
||||
JsExpression left = translateLeftExpression(context(), expression);
|
||||
JsExpression right = translateRightExpression(context(), expression);
|
||||
return new JsBinaryOperation(operator, left, right);
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
private JsExpression translateAsOverloadedBinaryOperation() {
|
||||
CallBuilder callBuilder = setReceiverAndArguments();
|
||||
ResolvedCall<?> resolvedCall1 =
|
||||
getResolvedCall(bindingContext(), expression.getOperationReference());
|
||||
JsExpression result = callBuilder.resolvedCall(resolvedCall1)
|
||||
.type(CallType.NORMAL).translate();
|
||||
return mayBeWrapWithNegation(result);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private CallBuilder setReceiverAndArguments() {
|
||||
CallBuilder callBuilder = CallBuilder.build(context());
|
||||
|
||||
JsExpression leftExpression = translateLeftExpression(context(), expression);
|
||||
JsExpression rightExpression = translateRightExpression(context(), expression);
|
||||
|
||||
if (isInOrNotInOperation(expression)) {
|
||||
return callBuilder.receiver(rightExpression).args(leftExpression);
|
||||
} else {
|
||||
return callBuilder.receiver(leftExpression).args(rightExpression);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression mayBeWrapWithNegation(@NotNull JsExpression result) {
|
||||
if (isNotInOperation(expression)) {
|
||||
return not(result);
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.operation;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsBinaryOperation;
|
||||
import com.google.dart.compiler.backend.js.ast.JsBinaryOperator;
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetBinaryExpression;
|
||||
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
|
||||
import org.jetbrains.jet.lexer.JetToken;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
import org.jetbrains.k2js.translate.intrinsic.CompareToIntrinsic;
|
||||
import org.jetbrains.k2js.translate.utils.TranslationUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptorForOperationExpression;
|
||||
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.isCompareTo;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken;
|
||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.*;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class CompareToTranslator extends AbstractTranslator {
|
||||
|
||||
public static boolean isCompareToCall(@NotNull JetBinaryExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
FunctionDescriptor operationDescriptor =
|
||||
getFunctionDescriptorForOperationExpression(context.bindingContext(), expression);
|
||||
|
||||
if (operationDescriptor == null) return false;
|
||||
|
||||
return (isCompareTo(operationDescriptor));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression translate(@NotNull JetBinaryExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return (new CompareToTranslator(expression, context)).translate();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final JetBinaryExpression expression;
|
||||
|
||||
@NotNull
|
||||
private final FunctionDescriptor descriptor;
|
||||
|
||||
private CompareToTranslator(@NotNull JetBinaryExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
super(context);
|
||||
this.expression = expression;
|
||||
FunctionDescriptor functionDescriptor =
|
||||
getFunctionDescriptorForOperationExpression(context.bindingContext(), expression);
|
||||
assert functionDescriptor != null : "CompareTo should always have a descriptor";
|
||||
this.descriptor = functionDescriptor;
|
||||
assert (OperatorConventions.COMPARISON_OPERATIONS.contains(getOperationToken(expression)));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression translate() {
|
||||
if (isIntrinsicOperation(context(), expression)) {
|
||||
return intrinsicCompareTo();
|
||||
}
|
||||
return overloadedCompareTo();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression overloadedCompareTo() {
|
||||
JsBinaryOperator correspondingOperator = OperatorTable.getBinaryOperator(getOperationToken(expression));
|
||||
JsExpression methodCall = BinaryOperationTranslator.translateAsOverloadedCall(expression, context());
|
||||
return new JsBinaryOperation(correspondingOperator, methodCall, TranslationUtils.zeroLiteral(context()));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression intrinsicCompareTo() {
|
||||
CompareToIntrinsic intrinsic = context().intrinsics().getCompareToIntrinsic(descriptor);
|
||||
intrinsic.setComparisonToken((JetToken) expression.getOperationToken());
|
||||
JsExpression left = translateLeftExpression(context(), expression);
|
||||
JsExpression right = translateRightExpression(context(), expression);
|
||||
return intrinsic.apply(left, Arrays.asList(right), context());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.operation;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetUnaryExpression;
|
||||
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
|
||||
import org.jetbrains.k2js.translate.context.TemporaryVariable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
import org.jetbrains.k2js.translate.reference.AccessTranslator;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.isStatement;
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.isVariableReassignment;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.*;
|
||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.isIntrinsicOperation;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
// TODO: provide better increment translator logic
|
||||
public abstract class IncrementTranslator extends AbstractTranslator {
|
||||
|
||||
public static boolean isIncrement(@NotNull JetUnaryExpression expression) {
|
||||
return OperatorConventions.INCREMENT_OPERATIONS.contains(getOperationToken(expression));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression translate(@NotNull JetUnaryExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
if (isIntrinsicOperation(context, expression)) {
|
||||
return IntrinsicIncrementTranslator.translate(expression, context);
|
||||
}
|
||||
return OverloadedIncrementTranslator.translate(expression, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected final JetUnaryExpression expression;
|
||||
@NotNull
|
||||
protected final AccessTranslator accessTranslator;
|
||||
private final boolean isVariableReassignment;
|
||||
|
||||
protected IncrementTranslator(@NotNull JetUnaryExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
super(context);
|
||||
this.expression = expression;
|
||||
this.isVariableReassignment = isVariableReassignment(context.bindingContext(), expression);
|
||||
JetExpression baseExpression = getBaseExpression(expression);
|
||||
this.accessTranslator = AccessTranslator.getAccessTranslator(baseExpression, context());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected JsExpression translateAsMethodCall() {
|
||||
if (returnValueIgnored() || isPrefix(expression)) {
|
||||
return asPrefix();
|
||||
}
|
||||
if (isVariableReassignment) {
|
||||
return asPostfixWithReassignment();
|
||||
} else {
|
||||
return asPostfixWithNoReassignment();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean returnValueIgnored() {
|
||||
return isStatement(bindingContext(), expression);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression asPrefix() {
|
||||
JsExpression getExpression = accessTranslator.translateAsGet();
|
||||
if (isVariableReassignment) {
|
||||
return variableReassignment(getExpression);
|
||||
}
|
||||
return operationExpression(getExpression);
|
||||
}
|
||||
|
||||
//TODO: decide if this expression can be optimised in case of direct access (not property)
|
||||
@NotNull
|
||||
private JsExpression asPostfixWithReassignment() {
|
||||
// code fragment: expr(a++)
|
||||
// generate: expr( (t1 = a, t2 = t1, a = t1.inc(), t2) )
|
||||
TemporaryVariable t1 = context().declareTemporary(accessTranslator.translateAsGet());
|
||||
TemporaryVariable t2 = context().declareTemporary(t1.reference());
|
||||
JsExpression variableReassignment = variableReassignment(t1.reference());
|
||||
return AstUtil.newSequence(t1.assignmentExpression(), t2.assignmentExpression(),
|
||||
variableReassignment, t2.reference());
|
||||
}
|
||||
|
||||
//TODO: TEST
|
||||
@NotNull
|
||||
private JsExpression asPostfixWithNoReassignment() {
|
||||
// code fragment: expr(a++)
|
||||
// generate: expr( (t1 = a, t2 = t1, t2.inc(), t1) )
|
||||
TemporaryVariable t1 = context().declareTemporary(accessTranslator.translateAsGet());
|
||||
TemporaryVariable t2 = context().declareTemporary(t1.reference());
|
||||
JsExpression methodCall = operationExpression(t2.reference());
|
||||
JsExpression returnedValue = t1.reference();
|
||||
return AstUtil.newSequence(t1.assignmentExpression(), t2.assignmentExpression(), methodCall, returnedValue);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression variableReassignment(@NotNull JsExpression toCallMethodUpon) {
|
||||
JsExpression overloadedMethodCallOnPropertyGetter = operationExpression(toCallMethodUpon);
|
||||
return accessTranslator.translateAsSet(overloadedMethodCallOnPropertyGetter);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
abstract JsExpression operationExpression(@NotNull JsExpression receiver);
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.operation;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsBinaryOperation;
|
||||
import com.google.dart.compiler.backend.js.ast.JsBinaryOperator;
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetBinaryExpression;
|
||||
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
|
||||
import org.jetbrains.jet.lexer.JetToken;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.reference.ReferenceAccessTranslator;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.isAssignment;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class IntrinsicAssignmentTranslator extends AssignmentTranslator {
|
||||
|
||||
|
||||
@NotNull
|
||||
public static JsExpression translate(@NotNull JetBinaryExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return (new IntrinsicAssignmentTranslator(expression, context)).translate();
|
||||
}
|
||||
|
||||
private IntrinsicAssignmentTranslator(@NotNull JetBinaryExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
super(expression, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected JsExpression translate() {
|
||||
if (isAssignment(getOperationToken(expression))) {
|
||||
return translateAsPlainAssignment();
|
||||
}
|
||||
return translateAsAssignmentOperation();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression translateAsAssignmentOperation() {
|
||||
if (accessTranslator instanceof ReferenceAccessTranslator) {
|
||||
return translateAsPlainAssignmentOperation();
|
||||
}
|
||||
return translateAsAssignToCounterpart();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression translateAsAssignToCounterpart() {
|
||||
JsBinaryOperator operator = getCounterpartOperator();
|
||||
JsBinaryOperation counterpartOperation =
|
||||
new JsBinaryOperation(operator, accessTranslator.translateAsGet(), right);
|
||||
return accessTranslator.translateAsSet(counterpartOperation);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsBinaryOperator getCounterpartOperator() {
|
||||
JetToken assignmentOperationToken = getOperationToken(expression);
|
||||
assert OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(assignmentOperationToken);
|
||||
JetToken counterpartToken = OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.get(assignmentOperationToken);
|
||||
assert OperatorTable.hasCorrespondingBinaryOperator(counterpartToken) :
|
||||
"Unsupported token encountered: " + counterpartToken.toString();
|
||||
return OperatorTable.getBinaryOperator(counterpartToken);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression translateAsPlainAssignmentOperation() {
|
||||
JsBinaryOperator operator = getAssignmentOperator();
|
||||
return new JsBinaryOperation(operator, accessTranslator.translateAsGet(), right);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsBinaryOperator getAssignmentOperator() {
|
||||
JetToken token = getOperationToken(expression);
|
||||
assert OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(token);
|
||||
assert OperatorTable.hasCorrespondingBinaryOperator(token) :
|
||||
"Unsupported token encountered: " + token.toString();
|
||||
return OperatorTable.getBinaryOperator(token);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression translateAsPlainAssignment() {
|
||||
return accessTranslator.translateAsSet(right);
|
||||
}
|
||||
}
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.operation;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetUnaryExpression;
|
||||
import org.jetbrains.jet.lexer.JetToken;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.reference.ReferenceAccessTranslator;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getOperationToken;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.isPrefix;
|
||||
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class IntrinsicIncrementTranslator extends IncrementTranslator {
|
||||
|
||||
|
||||
@NotNull
|
||||
public static JsExpression translate(@NotNull JetUnaryExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return (new IntrinsicIncrementTranslator(expression, context))
|
||||
.translate();
|
||||
}
|
||||
|
||||
private IntrinsicIncrementTranslator(@NotNull JetUnaryExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
super(expression, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected JsExpression translate() {
|
||||
if (isPrimitiveExpressionIncrement()) {
|
||||
return jsUnaryExpression();
|
||||
}
|
||||
return translateAsMethodCall();
|
||||
}
|
||||
|
||||
private boolean isPrimitiveExpressionIncrement() {
|
||||
return accessTranslator instanceof ReferenceAccessTranslator;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression jsUnaryExpression() {
|
||||
JsUnaryOperator operator = OperatorTable.getUnaryOperator(getOperationToken(expression));
|
||||
JsExpression getExpression = accessTranslator.translateAsGet();
|
||||
if (isPrefix(expression)) {
|
||||
return new JsPrefixOperation(operator, getExpression);
|
||||
} else {
|
||||
return new JsPostfixOperation(operator, getExpression);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected JsExpression operationExpression(@NotNull JsExpression receiver) {
|
||||
return unaryAsBinary(receiver);
|
||||
}
|
||||
|
||||
public JsBinaryOperation unaryAsBinary(@NotNull JsExpression leftExpression) {
|
||||
JsNumberLiteral oneLiteral = program().getNumberLiteral(1);
|
||||
JetToken token = getOperationToken(expression);
|
||||
if (token.equals(JetTokens.PLUSPLUS)) {
|
||||
return new JsBinaryOperation(JsBinaryOperator.ADD, leftExpression, oneLiteral);
|
||||
}
|
||||
if (token.equals(JetTokens.MINUSMINUS)) {
|
||||
return new JsBinaryOperation(JsBinaryOperator.SUB, leftExpression, oneLiteral);
|
||||
}
|
||||
throw new AssertionError("This method should be called only for increment and decrement operators");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.operation;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsBinaryOperator;
|
||||
import com.google.dart.compiler.backend.js.ast.JsUnaryOperator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lexer.JetToken;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
|
||||
//TODO: refactor using guava builders
|
||||
public final class OperatorTable {
|
||||
|
||||
private static final Map<JetToken, JsBinaryOperator> binaryOperatorsMap = new HashMap<JetToken, JsBinaryOperator>();
|
||||
private static final Map<JetToken, JsUnaryOperator> unaryOperatorsMap = new HashMap<JetToken, JsUnaryOperator>();
|
||||
|
||||
static {
|
||||
unaryOperatorsMap.put(JetTokens.PLUSPLUS, JsUnaryOperator.INC); //++
|
||||
unaryOperatorsMap.put(JetTokens.MINUSMINUS, JsUnaryOperator.DEC); //--
|
||||
unaryOperatorsMap.put(JetTokens.EXCL, JsUnaryOperator.NOT); //!
|
||||
unaryOperatorsMap.put(JetTokens.MINUS, JsUnaryOperator.NEG); //-
|
||||
unaryOperatorsMap.put(JetTokens.PLUS, JsUnaryOperator.POS); //+
|
||||
}
|
||||
|
||||
//TODO : not all operators , add and test bit operators
|
||||
static {
|
||||
binaryOperatorsMap.put(JetTokens.PLUS, JsBinaryOperator.ADD);
|
||||
binaryOperatorsMap.put(JetTokens.MINUS, JsBinaryOperator.SUB);
|
||||
binaryOperatorsMap.put(JetTokens.MUL, JsBinaryOperator.MUL);
|
||||
binaryOperatorsMap.put(JetTokens.DIV, JsBinaryOperator.DIV);
|
||||
binaryOperatorsMap.put(JetTokens.EQ, JsBinaryOperator.ASG);
|
||||
binaryOperatorsMap.put(JetTokens.GT, JsBinaryOperator.GT);
|
||||
binaryOperatorsMap.put(JetTokens.GTEQ, JsBinaryOperator.GTE);
|
||||
binaryOperatorsMap.put(JetTokens.LT, JsBinaryOperator.LT);
|
||||
binaryOperatorsMap.put(JetTokens.LTEQ, JsBinaryOperator.LTE);
|
||||
binaryOperatorsMap.put(JetTokens.EQEQ, JsBinaryOperator.REF_EQ);
|
||||
binaryOperatorsMap.put(JetTokens.ANDAND, JsBinaryOperator.AND);
|
||||
binaryOperatorsMap.put(JetTokens.OROR, JsBinaryOperator.OR);
|
||||
binaryOperatorsMap.put(JetTokens.EXCLEQ, JsBinaryOperator.NEQ);
|
||||
binaryOperatorsMap.put(JetTokens.PERC, JsBinaryOperator.MOD);
|
||||
binaryOperatorsMap.put(JetTokens.PLUSEQ, JsBinaryOperator.ASG_ADD);
|
||||
binaryOperatorsMap.put(JetTokens.MINUSEQ, JsBinaryOperator.ASG_SUB);
|
||||
binaryOperatorsMap.put(JetTokens.DIVEQ, JsBinaryOperator.ASG_DIV);
|
||||
binaryOperatorsMap.put(JetTokens.MULTEQ, JsBinaryOperator.ASG_MUL);
|
||||
binaryOperatorsMap.put(JetTokens.PERCEQ, JsBinaryOperator.ASG_MOD);
|
||||
}
|
||||
|
||||
|
||||
public static boolean hasCorrespondingBinaryOperator(@NotNull JetToken token) {
|
||||
return binaryOperatorsMap.containsKey(token);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static public JsBinaryOperator getBinaryOperator(@NotNull JetToken token) {
|
||||
assert JetTokens.OPERATIONS.contains(token) : "Token should represent an operation!";
|
||||
return binaryOperatorsMap.get(token);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static public JsUnaryOperator getUnaryOperator(@NotNull JetToken token) {
|
||||
assert JetTokens.OPERATIONS.contains(token) : "Token should represent an operation!";
|
||||
return unaryOperatorsMap.get(token);
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.operation;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.backend.js.ast.JsNameRef;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetBinaryExpression;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.getMethodReferenceForOverloadedOperation;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class OverloadedAssignmentTranslator extends AssignmentTranslator {
|
||||
|
||||
@NotNull
|
||||
public static JsExpression translate(@NotNull JetBinaryExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return (new OverloadedAssignmentTranslator(expression, context)).translate();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final JsNameRef operationReference;
|
||||
|
||||
private OverloadedAssignmentTranslator(@NotNull JetBinaryExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
super(expression, context);
|
||||
this.operationReference = getMethodReferenceForOverloadedOperation(context, expression);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected JsExpression translate() {
|
||||
if (isVariableReassignment) {
|
||||
return reassignment();
|
||||
}
|
||||
return overloadedMethodInvocation();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression reassignment() {
|
||||
return accessTranslator.translateAsSet(overloadedMethodInvocation());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression overloadedMethodInvocation() {
|
||||
AstUtil.setQualifier(operationReference, accessTranslator.translateAsGet());
|
||||
return AstUtil.newInvocation(operationReference, right);
|
||||
}
|
||||
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.operation;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.backend.js.ast.JsNameRef;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetUnaryExpression;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.getMethodReferenceForOverloadedOperation;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class OverloadedIncrementTranslator extends IncrementTranslator {
|
||||
|
||||
@NotNull
|
||||
public static JsExpression translate(@NotNull JetUnaryExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return (new OverloadedIncrementTranslator(expression, context))
|
||||
.translate();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final JsNameRef operationReference;
|
||||
|
||||
private OverloadedIncrementTranslator(@NotNull JetUnaryExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
super(expression, context);
|
||||
this.operationReference = getMethodReferenceForOverloadedOperation(context, expression);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected JsExpression translate() {
|
||||
return translateAsMethodCall();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected JsExpression operationExpression(@NotNull JsExpression receiver) {
|
||||
AstUtil.setQualifier(operationReference, receiver);
|
||||
return AstUtil.newInvocation(operationReference);
|
||||
}
|
||||
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.operation;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetUnaryExpression;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.reference.CallBuilder;
|
||||
import org.jetbrains.k2js.translate.reference.CallType;
|
||||
import org.jetbrains.k2js.translate.utils.TranslationUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getResolvedCall;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
|
||||
public final class UnaryOperationTranslator {
|
||||
|
||||
@NotNull
|
||||
public static JsExpression translate(@NotNull JetUnaryExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
if (IncrementTranslator.isIncrement(expression)) {
|
||||
return IncrementTranslator.translate(expression, context);
|
||||
}
|
||||
return translateAsCall(expression, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static JsExpression translateAsCall(@NotNull JetUnaryExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return CallBuilder.build(context)
|
||||
.receiver(TranslationUtils.translateBaseExpression(context, expression))
|
||||
.args(Collections.<JsExpression>emptyList())
|
||||
.resolvedCall(getResolvedCall(context.bindingContext(), expression.getOperationReference()))
|
||||
.type(CallType.NORMAL).translate();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.reference;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
* <p/>
|
||||
* Abstract entity for language constructs that you can get/set. Also dispatches to the real implemntation.
|
||||
*/
|
||||
public abstract class AccessTranslator extends AbstractTranslator {
|
||||
|
||||
//TODO: this piece of code represents dangerously convoluted logic, think of the ways it can be improved
|
||||
@NotNull
|
||||
public static AccessTranslator getAccessTranslator(@NotNull JetExpression referenceExpression,
|
||||
@NotNull TranslationContext context) {
|
||||
assert ((referenceExpression instanceof JetReferenceExpression) ||
|
||||
(referenceExpression instanceof JetQualifiedExpression));
|
||||
if (PropertyAccessTranslator.canBePropertyAccess(referenceExpression, context)) {
|
||||
if (referenceExpression instanceof JetQualifiedExpression) {
|
||||
return QualifiedExpressionTranslator.getAccessTranslator((JetQualifiedExpression) referenceExpression, context);
|
||||
}
|
||||
assert referenceExpression instanceof JetSimpleNameExpression;
|
||||
return PropertyAccessTranslator.newInstance((JetSimpleNameExpression) referenceExpression,
|
||||
null, CallType.NORMAL, context);
|
||||
}
|
||||
if (referenceExpression instanceof JetArrayAccessExpression) {
|
||||
return ArrayAccessTranslator.newInstance((JetArrayAccessExpression) referenceExpression, context);
|
||||
}
|
||||
return ReferenceAccessTranslator.newInstance((JetSimpleNameExpression) referenceExpression, context);
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
public static JsExpression translateAsGet(@NotNull JetReferenceExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return (getAccessTranslator(expression, context)).translateAsGet();
|
||||
}
|
||||
|
||||
|
||||
protected AccessTranslator(@Deprecated TranslationContext context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public abstract JsExpression translateAsGet();
|
||||
|
||||
public abstract JsExpression translateAsSet(@NotNull JsExpression setTo);
|
||||
|
||||
}
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.reference;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetArrayAccessExpression;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.Translation;
|
||||
import org.jetbrains.k2js.translate.utils.BindingUtils;
|
||||
import org.jetbrains.k2js.translate.utils.TranslationUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForReferenceExpression;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
|
||||
//TODO: inspect not clear how the class handles set and get operations differently
|
||||
public final class ArrayAccessTranslator extends AccessTranslator {
|
||||
|
||||
/*package*/
|
||||
static ArrayAccessTranslator newInstance(@NotNull JetArrayAccessExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return new ArrayAccessTranslator(expression, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final JetArrayAccessExpression expression;
|
||||
@NotNull
|
||||
private final FunctionDescriptor methodDescriptor;
|
||||
|
||||
private ArrayAccessTranslator(@NotNull JetArrayAccessExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
super(context);
|
||||
this.expression = expression;
|
||||
//TODO: that is strange
|
||||
this.methodDescriptor = (FunctionDescriptor)
|
||||
getDescriptorForReferenceExpression(context.bindingContext(), expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsExpression translateAsGet() {
|
||||
List<JsExpression> arguments = translateIndexExpressions();
|
||||
return translateAsMethodCall(arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsExpression translateAsSet(@NotNull JsExpression expression) {
|
||||
|
||||
List<JsExpression> arguments = translateIndexExpressions();
|
||||
arguments.add(expression);
|
||||
return translateAsMethodCall(arguments);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression translateAsMethodCall(@NotNull List<JsExpression> arguments) {
|
||||
return CallBuilder.build(context())
|
||||
.receiver(translateArrayExpression())
|
||||
.args(arguments)
|
||||
.resolvedCall(BindingUtils.getResolvedCall(bindingContext(), expression))
|
||||
.descriptor(methodDescriptor)
|
||||
.translate();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<JsExpression> translateIndexExpressions() {
|
||||
return TranslationUtils.translateExpressionList(context(), expression.getIndexExpressions());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression translateArrayExpression() {
|
||||
return Translation.translateAsExpression(expression.getArrayExpression(), context());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.reference;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.calls.ResolvedCallImpl;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class CallBuilder {
|
||||
|
||||
public static CallBuilder build(@NotNull TranslationContext context) {
|
||||
return new CallBuilder(context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final TranslationContext context;
|
||||
@Nullable
|
||||
private /*var*/ JsExpression receiver = null;
|
||||
@NotNull
|
||||
private final List<JsExpression> args = Lists.newArrayList();
|
||||
@NotNull
|
||||
private /*var*/ CallType callType = CallType.NORMAL;
|
||||
@Nullable
|
||||
private /*var*/ ResolvedCall<?> resolvedCall = null;
|
||||
@Nullable
|
||||
private /*var*/ CallableDescriptor descriptor = null;
|
||||
@Nullable
|
||||
private /*var*/ JsExpression callee = null;
|
||||
|
||||
|
||||
private CallBuilder(@NotNull TranslationContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public CallBuilder receiver(@Nullable JsExpression receiver) {
|
||||
this.receiver = receiver;
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public CallBuilder args(@NotNull List<JsExpression> args) {
|
||||
assert this.args.isEmpty();
|
||||
this.args.addAll(args);
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public CallBuilder args(@NotNull JsExpression... args) {
|
||||
return args(Arrays.asList(args));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public CallBuilder descriptor(@NotNull CallableDescriptor descriptor) {
|
||||
this.descriptor = descriptor;
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public CallBuilder callee(@Nullable JsExpression callee) {
|
||||
this.callee = callee;
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public CallBuilder resolvedCall(@NotNull ResolvedCall<?> call) {
|
||||
this.resolvedCall = call;
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public CallBuilder type(@NotNull CallType type) {
|
||||
this.callType = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
//TODO: must be private
|
||||
@NotNull
|
||||
public CallTranslator finish() {
|
||||
if (resolvedCall == null) {
|
||||
assert descriptor != null;
|
||||
resolvedCall = ResolvedCallImpl.create(descriptor);
|
||||
}
|
||||
if (descriptor == null) {
|
||||
descriptor = resolvedCall.getCandidateDescriptor().getOriginal();
|
||||
}
|
||||
assert resolvedCall != null;
|
||||
return new CallTranslator(receiver, callee, args, resolvedCall, descriptor, callType, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsExpression translate() {
|
||||
return finish().translate();
|
||||
}
|
||||
/*
|
||||
@NotNull
|
||||
private CallTranslator buildFromUnary(@NotNull JetUnaryExpression unaryExpression) {
|
||||
JsExpression receiver = TranslationUtils.translateBaseExpression(context, unaryExpression);
|
||||
List<JsExpression> arguments = Collections.emptyList();
|
||||
ResolvedCall<?> resolvedCall =
|
||||
getResolvedCall(context.bindingContext(), unaryExpression.getOperationReference());
|
||||
return new CallTranslator(receiver, null, arguments, resolvedCall, null, CallType.NORMAL, context);
|
||||
}
|
||||
|
||||
//TODO: method too long
|
||||
@NotNull
|
||||
private CallTranslator buildFromBinary(@NotNull JetBinaryExpression binaryExpression,
|
||||
boolean swapReceiverAndArgument) {
|
||||
|
||||
JsExpression leftExpression = translateLeftExpression(context, binaryExpression);
|
||||
JsExpression rightExpression = translateRightExpression(context, binaryExpression);
|
||||
|
||||
JsExpression receiver;
|
||||
List<JsExpression> arguments;
|
||||
if (swapReceiverAndArgument) {
|
||||
receiver = rightExpression;
|
||||
arguments = Arrays.asList(leftExpression);
|
||||
} else {
|
||||
receiver = leftExpression;
|
||||
arguments = Arrays.asList(rightExpression);
|
||||
}
|
||||
|
||||
ResolvedCall<?> resolvedCall =
|
||||
getResolvedCall(context.bindingContext(), binaryExpression.getOperationReference());
|
||||
return new CallTranslator(receiver, null, arguments, resolvedCall, null, CallType.NORMAL, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private CallTranslator buildFromCallExpression(@NotNull JetCallExpression callExpression,
|
||||
@Nullable JsExpression receiver,
|
||||
@NotNull CallType callType) {
|
||||
ResolvedCall<?> resolvedCall = getResolvedCallForCallExpression(context.bindingContext(), callExpression);
|
||||
List<JsExpression> arguments = translateArgumentsForCallExpression(callExpression, context);
|
||||
JsExpression callee = null;
|
||||
if (resolvedCall.getCandidateDescriptor() instanceof ExpressionAsFunctionDescriptor) {
|
||||
callee = Translation.translateAsExpression(getCallee(callExpression), context);
|
||||
}
|
||||
return new CallTranslator(receiver, callee, arguments, resolvedCall, null, callType, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<JsExpression> translateArgumentsForCallExpression(@NotNull JetCallExpression callExpression,
|
||||
@NotNull TranslationContext context) {
|
||||
List<JsExpression> result = new ArrayList<JsExpression>();
|
||||
ResolvedCall<?> resolvedCall = getResolvedCallForCallExpression(context.bindingContext(), callExpression);
|
||||
Map<ValueParameterDescriptor, ResolvedValueArgument> formalToActualArguments = resolvedCall.getValueArguments();
|
||||
for (ValueParameterDescriptor parameterDescriptor : resolvedCall.getResultingDescriptor().getValueParameters()) {
|
||||
ResolvedValueArgument actualArgument = formalToActualArguments.get(parameterDescriptor);
|
||||
result.add(translateSingleArgument(actualArgument, parameterDescriptor));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//TODO: refactor
|
||||
@NotNull
|
||||
private JsExpression translateSingleArgument(@NotNull ResolvedValueArgument actualArgument,
|
||||
@NotNull ValueParameterDescriptor parameterDescriptor) {
|
||||
List<JetExpression> argumentExpressions = actualArgument.getArgumentExpressions();
|
||||
if (actualArgument instanceof VarargValueArgument) {
|
||||
return translateVarargArgument(argumentExpressions);
|
||||
}
|
||||
if (actualArgument instanceof DefaultValueArgument) {
|
||||
JetExpression defaultArgument = getDefaultArgument(context.bindingContext(), parameterDescriptor);
|
||||
return Translation.translateAsExpression(defaultArgument, context);
|
||||
}
|
||||
assert actualArgument instanceof ExpressionValueArgument;
|
||||
assert argumentExpressions.size() == 1;
|
||||
return Translation.translateAsExpression(argumentExpressions.get(0), context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression translateVarargArgument(@NotNull List<JetExpression> arguments) {
|
||||
JsArrayLiteral varargArgument = new JsArrayLiteral();
|
||||
for (JetExpression argument : arguments) {
|
||||
varargArgument.getExpressions().add(Translation.translateAsExpression(argument, context));
|
||||
}
|
||||
return varargArgument;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
}
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.reference;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.dart.compiler.backend.js.ast.JsArrayLiteral;
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetCallExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.resolve.calls.*;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
import org.jetbrains.k2js.translate.general.Translation;
|
||||
import org.jetbrains.k2js.translate.utils.AnnotationsUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getDefaultArgument;
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getResolvedCallForCallExpression;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getCallee;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class CallExpressionTranslator extends AbstractTranslator {
|
||||
|
||||
@NotNull
|
||||
public static JsExpression translate(@NotNull JetCallExpression expression,
|
||||
@Nullable JsExpression receiver,
|
||||
@NotNull CallType callType,
|
||||
@NotNull TranslationContext context) {
|
||||
return (new CallExpressionTranslator(expression, context)).translate(receiver, callType);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final JetCallExpression expression;
|
||||
@NotNull
|
||||
private final ResolvedCall<?> resolvedCall;
|
||||
private final boolean isNativeFunctionCall;
|
||||
|
||||
private CallExpressionTranslator(@NotNull JetCallExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
super(context);
|
||||
this.expression = expression;
|
||||
this.resolvedCall = getResolvedCallForCallExpression(bindingContext(), expression);
|
||||
this.isNativeFunctionCall = AnnotationsUtils.isNativeObject(resolvedCall.getCandidateDescriptor());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression translate(@Nullable JsExpression receiver,
|
||||
@NotNull CallType callType) {
|
||||
return CallBuilder.build(context())
|
||||
.receiver(receiver)
|
||||
.callee(getCalleeExpression())
|
||||
.args(translateArguments())
|
||||
.resolvedCall(resolvedCall)
|
||||
.type(callType)
|
||||
.translate();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private JsExpression getCalleeExpression() {
|
||||
if (resolvedCall.getCandidateDescriptor() instanceof ExpressionAsFunctionDescriptor) {
|
||||
return Translation.translateAsExpression(getCallee(expression), context());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<JsExpression> translateArguments() {
|
||||
List<JsExpression> result = new ArrayList<JsExpression>();
|
||||
ResolvedCall<?> resolvedCall = getResolvedCallForCallExpression(bindingContext(), expression);
|
||||
for (ValueParameterDescriptor parameterDescriptor : resolvedCall.getResultingDescriptor().getValueParameters()) {
|
||||
ResolvedValueArgument actualArgument = resolvedCall.getValueArgumentsByIndex().get(parameterDescriptor.getIndex());
|
||||
result.addAll(translateSingleArgument(actualArgument, parameterDescriptor));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<JsExpression> translateSingleArgument(@NotNull ResolvedValueArgument actualArgument,
|
||||
@NotNull ValueParameterDescriptor parameterDescriptor) {
|
||||
List<JetExpression> argumentExpressions = actualArgument.getArgumentExpressions();
|
||||
if (actualArgument instanceof VarargValueArgument) {
|
||||
return translateVarargArgument(argumentExpressions);
|
||||
}
|
||||
if (actualArgument instanceof DefaultValueArgument) {
|
||||
JetExpression defaultArgument = getDefaultArgument(bindingContext(), parameterDescriptor);
|
||||
return Arrays.asList(Translation.translateAsExpression(defaultArgument, context()));
|
||||
}
|
||||
assert actualArgument instanceof ExpressionValueArgument;
|
||||
assert argumentExpressions.size() == 1;
|
||||
return Arrays.asList(Translation.translateAsExpression(argumentExpressions.get(0), context()));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<JsExpression> translateVarargArgument(@NotNull List<JetExpression> arguments) {
|
||||
List<JsExpression> translatedArgs = Lists.newArrayList();
|
||||
for (JetExpression argument : arguments) {
|
||||
translatedArgs.add(Translation.translateAsExpression(argument, context()));
|
||||
}
|
||||
if (isNativeFunctionCall) {
|
||||
return translatedArgs;
|
||||
}
|
||||
return wrapInArrayLiteral(translatedArgs);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<JsExpression> wrapInArrayLiteral(@NotNull List<JsExpression> translatedArgs) {
|
||||
JsArrayLiteral argsWrappedInArray = new JsArrayLiteral();
|
||||
argsWrappedInArray.getExpressions().addAll(translatedArgs);
|
||||
return Arrays.<JsExpression>asList(argsWrappedInArray);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.reference;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.backend.js.ast.JsInvocation;
|
||||
import com.google.dart.compiler.backend.js.ast.JsNameRef;
|
||||
import com.google.dart.compiler.backend.js.ast.JsNew;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.ExpressionAsFunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.general.AbstractTranslator;
|
||||
import org.jetbrains.k2js.translate.intrinsic.FunctionIntrinsic;
|
||||
import org.jetbrains.k2js.translate.utils.AnnotationsUtils;
|
||||
import org.jetbrains.k2js.translate.utils.TranslationUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.*;
|
||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.getThisObject;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
//TODO: write tests on calling backing fields as functions
|
||||
public final class CallTranslator extends AbstractTranslator {
|
||||
|
||||
private static class CallParameters {
|
||||
|
||||
public CallParameters(@Nullable JsExpression receiver, @NotNull JsExpression functionReference) {
|
||||
this.receiver = receiver;
|
||||
this.functionReference = functionReference;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public /*var*/ JsExpression receiver;
|
||||
@NotNull
|
||||
public /*var*/ JsExpression functionReference;
|
||||
}
|
||||
|
||||
//NOTE: receiver may mean this object as well
|
||||
@Nullable
|
||||
private /*var*/ JsExpression receiver;
|
||||
|
||||
@Nullable
|
||||
private final JsExpression callee;
|
||||
|
||||
@NotNull
|
||||
private final List<JsExpression> arguments;
|
||||
|
||||
@NotNull
|
||||
private final ResolvedCall<?> resolvedCall;
|
||||
|
||||
@NotNull
|
||||
private final CallableDescriptor descriptor;
|
||||
|
||||
@NotNull
|
||||
private final CallType callType;
|
||||
|
||||
/*package*/ CallTranslator(@Nullable JsExpression receiver, @Nullable JsExpression callee,
|
||||
@NotNull List<JsExpression> arguments,
|
||||
@NotNull ResolvedCall<? extends CallableDescriptor> resolvedCall,
|
||||
@NotNull CallableDescriptor descriptorToCall,
|
||||
@NotNull CallType callType,
|
||||
@NotNull TranslationContext context) {
|
||||
super(context);
|
||||
this.receiver = receiver;
|
||||
this.arguments = arguments;
|
||||
this.resolvedCall = resolvedCall;
|
||||
this.callType = callType;
|
||||
this.descriptor = descriptorToCall;
|
||||
this.callee = callee;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
/*package*/ JsExpression translate() {
|
||||
//NOTE: treat native extension function calls as usual calls
|
||||
if (isIntrinsic()) {
|
||||
return intrinsicInvocation();
|
||||
}
|
||||
if (isConstructor()) {
|
||||
return constructorCall();
|
||||
}
|
||||
if (isNative()) {
|
||||
return methodCall();
|
||||
}
|
||||
if (isExtensionFunctionLiteral()) {
|
||||
return extensionFunctionLiteralCall();
|
||||
}
|
||||
if (isExtensionFunction()) {
|
||||
return extensionFunctionCall();
|
||||
}
|
||||
return methodCall();
|
||||
}
|
||||
|
||||
private boolean isIntrinsic() {
|
||||
return context().intrinsics().isIntrinsic(descriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression intrinsicInvocation() {
|
||||
assert descriptor instanceof FunctionDescriptor;
|
||||
FunctionIntrinsic functionIntrinsic =
|
||||
context().intrinsics().getFunctionIntrinsic((FunctionDescriptor) descriptor);
|
||||
JsExpression receiverExpression = resolveThisObject(/*do not get qualifier*/false);
|
||||
return functionIntrinsic.apply(receiverExpression, arguments, context());
|
||||
}
|
||||
|
||||
private boolean isConstructor() {
|
||||
return isConstructorDescriptor(descriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression constructorCall() {
|
||||
JsExpression constructorReference = translateAsFunctionWithNoThisObject(descriptor);
|
||||
JsNew constructorCall = new JsNew(constructorReference);
|
||||
constructorCall.setArguments(arguments);
|
||||
return constructorCall;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression translateAsFunctionWithNoThisObject(@NotNull DeclarationDescriptor descriptor) {
|
||||
return ReferenceTranslator.translateAsFQReference(descriptor, context());
|
||||
}
|
||||
|
||||
private boolean isNative() {
|
||||
return AnnotationsUtils.isNativeObject(descriptor);
|
||||
}
|
||||
|
||||
private boolean isExtensionFunctionLiteral() {
|
||||
boolean isLiteral = descriptor instanceof VariableAsFunctionDescriptor
|
||||
|| descriptor instanceof ExpressionAsFunctionDescriptor;
|
||||
return isExtensionFunction() && isLiteral;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression extensionFunctionLiteralCall() {
|
||||
JsExpression realReceiver = getExtensionFunctionCallReceiver();
|
||||
return callType.constructCall(realReceiver, new CallType.CallConstructor() {
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression construct(@Nullable JsExpression receiver) {
|
||||
assert receiver != null : "Could not be null for extensions";
|
||||
return constructExtensionLiteralCall(receiver);
|
||||
}
|
||||
}, context());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression constructExtensionLiteralCall(@NotNull JsExpression realReceiver) {
|
||||
List<JsExpression> callArguments = generateExtensionCallArgumentList(realReceiver);
|
||||
JsInvocation callMethodInvocation = generateCallMethodInvocation();
|
||||
callMethodInvocation.setArguments(callArguments);
|
||||
return callMethodInvocation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsInvocation generateCallMethodInvocation() {
|
||||
JsNameRef callMethodNameRef = AstUtil.newQualifiedNameRef("call");
|
||||
JsInvocation callMethodInvocation = new JsInvocation();
|
||||
callMethodInvocation.setQualifier(callMethodNameRef);
|
||||
AstUtil.setQualifier(callMethodInvocation, callParameters().functionReference);
|
||||
return callMethodInvocation;
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnnecessaryLocalVariable")
|
||||
private boolean isExtensionFunction() {
|
||||
boolean hasReceiver = resolvedCall.getReceiverArgument().exists();
|
||||
return hasReceiver;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression extensionFunctionCall() {
|
||||
JsExpression realReceiver = getExtensionFunctionCallReceiver();
|
||||
return callType.constructCall(realReceiver, new CallType.CallConstructor() {
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression construct(@Nullable JsExpression receiver) {
|
||||
assert receiver != null : "Could not be null for extensions";
|
||||
return constructExtensionFunctionCall(receiver);
|
||||
}
|
||||
}, context());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression getExtensionFunctionCallReceiver() {
|
||||
if (receiver != null) {
|
||||
JsExpression result = receiver;
|
||||
//Now the rest of the code can work as if it was simple method invocation
|
||||
receiver = null;
|
||||
return result;
|
||||
}
|
||||
DeclarationDescriptor expectedReceiverDescriptor = getExpectedReceiverDescriptor(descriptor);
|
||||
assert expectedReceiverDescriptor != null;
|
||||
return getThisObject(context(), expectedReceiverDescriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression constructExtensionFunctionCall(@NotNull JsExpression receiver) {
|
||||
List<JsExpression> argumentList = generateExtensionCallArgumentList(receiver);
|
||||
JsExpression functionReference = callParameters().functionReference;
|
||||
AstUtil.setQualifier(functionReference, callParameters().receiver);
|
||||
return AstUtil.newInvocation(functionReference, argumentList);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<JsExpression> generateExtensionCallArgumentList(@NotNull JsExpression receiver) {
|
||||
List<JsExpression> argumentList = new ArrayList<JsExpression>();
|
||||
assert this.receiver == null : "Should be null at that point";
|
||||
argumentList.add(receiver);
|
||||
argumentList.addAll(arguments);
|
||||
return argumentList;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression methodCall() {
|
||||
final CallParameters callParameters = callParameters();
|
||||
return callType.constructCall(callParameters.receiver, new CallType.CallConstructor() {
|
||||
@NotNull
|
||||
@Override
|
||||
public JsExpression construct(@Nullable JsExpression receiver) {
|
||||
JsExpression functionReference = callParameters.functionReference;
|
||||
if (receiver != null) {
|
||||
AstUtil.setQualifier(functionReference, receiver);
|
||||
}
|
||||
return AstUtil.newInvocation(functionReference, arguments);
|
||||
}
|
||||
}, context());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private CallParameters callParameters() {
|
||||
if (callee != null) {
|
||||
return new CallParameters(null, callee);
|
||||
}
|
||||
JsExpression thisObject = resolveThisObject(/*just get qualifier if null*/ true);
|
||||
JsExpression functionReference = functionReference();
|
||||
return new CallParameters(thisObject, functionReference);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression functionReference() {
|
||||
if (!isVariableAsFunction(descriptor)) {
|
||||
return ReferenceTranslator.translateAsLocalNameReference(descriptor, context());
|
||||
}
|
||||
VariableDescriptor variableDescriptor =
|
||||
getVariableDescriptorForVariableAsFunction((VariableAsFunctionDescriptor) descriptor);
|
||||
if (variableDescriptor instanceof PropertyDescriptor) {
|
||||
return getterCall((PropertyDescriptor) variableDescriptor);
|
||||
}
|
||||
return ReferenceTranslator.translateAsLocalNameReference(variableDescriptor, context());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression getterCall(@NotNull PropertyDescriptor variableDescriptor) {
|
||||
//TODO: call type?
|
||||
return PropertyAccessTranslator.translateAsPropertyGetterCall(variableDescriptor, resolvedCall, context());
|
||||
}
|
||||
|
||||
//TODO: refactor
|
||||
@Nullable
|
||||
private JsExpression resolveThisObject(boolean getQualifierIfNull) {
|
||||
if (receiver != null) {
|
||||
return receiver;
|
||||
}
|
||||
ReceiverDescriptor thisObject = resolvedCall.getThisObject();
|
||||
if (thisObject.exists()) {
|
||||
DeclarationDescriptor expectedThisDescriptor = getDeclarationDescriptorForReceiver(thisObject);
|
||||
return TranslationUtils.getThisObject(context(), expectedThisDescriptor);
|
||||
}
|
||||
if (getQualifierIfNull) {
|
||||
return context().getQualifierForDescriptor(descriptor);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.reference;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsBinaryOperation;
|
||||
import com.google.dart.compiler.backend.js.ast.JsConditional;
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.backend.js.ast.JsNullLiteral;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.psi.JetDotQualifiedExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetQualifiedExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetSafeQualifiedExpression;
|
||||
import org.jetbrains.k2js.translate.context.TemporaryVariable;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
|
||||
import static com.google.dart.compiler.util.AstUtil.newSequence;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public enum CallType {
|
||||
SAFE {
|
||||
@NotNull
|
||||
@Override
|
||||
JsExpression constructCall(@Nullable JsExpression receiver, @NotNull CallConstructor constructor,
|
||||
@NotNull TranslationContext context) {
|
||||
assert receiver != null;
|
||||
TemporaryVariable temporaryVariable = context.declareTemporary(receiver);
|
||||
JsNullLiteral nullLiteral = context.program().getNullLiteral();
|
||||
//TODO: find similar not null checks
|
||||
JsBinaryOperation notNullCheck = AstUtil.notEqual(temporaryVariable.reference(), nullLiteral);
|
||||
JsConditional callMethodIfNotNullElseNull =
|
||||
new JsConditional(notNullCheck, constructor.construct(temporaryVariable.reference()), nullLiteral);
|
||||
return newSequence(temporaryVariable.assignmentExpression(), callMethodIfNotNullElseNull);
|
||||
}
|
||||
},
|
||||
//TODO: bang qualifier is not implemented in frontend for now
|
||||
// BANG,
|
||||
NORMAL {
|
||||
@NotNull
|
||||
@Override
|
||||
JsExpression constructCall(@Nullable JsExpression receiver, @NotNull CallConstructor constructor,
|
||||
@NotNull TranslationContext context) {
|
||||
return constructor.construct(receiver);
|
||||
}
|
||||
};
|
||||
|
||||
@NotNull
|
||||
abstract JsExpression constructCall(@Nullable JsExpression receiver, @NotNull CallConstructor constructor,
|
||||
@NotNull TranslationContext context);
|
||||
|
||||
@NotNull
|
||||
public static CallType getCallTypeForQualifiedExpression(@NotNull JetQualifiedExpression expression) {
|
||||
if (expression instanceof JetSafeQualifiedExpression) {
|
||||
return SAFE;
|
||||
}
|
||||
assert expression instanceof JetDotQualifiedExpression;
|
||||
return NORMAL;
|
||||
}
|
||||
|
||||
public interface CallConstructor {
|
||||
@NotNull
|
||||
JsExpression construct(@Nullable JsExpression receiver);
|
||||
}
|
||||
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.reference;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.PropertyGetterDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.PropertySetterDescriptor;
|
||||
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
* <p/>
|
||||
* For properies /w accessors.
|
||||
*/
|
||||
public final class KotlinPropertyAccessTranslator extends PropertyAccessTranslator {
|
||||
|
||||
@Nullable
|
||||
private final JsExpression qualifier;
|
||||
@NotNull
|
||||
private final PropertyDescriptor propertyDescriptor;
|
||||
@NotNull
|
||||
ResolvedCall<?> resolvedCall;
|
||||
|
||||
//TODO: too many params in constructor
|
||||
/*package*/ KotlinPropertyAccessTranslator(@NotNull PropertyDescriptor descriptor,
|
||||
@Nullable JsExpression qualifier,
|
||||
@NotNull ResolvedCall<?> resolvedCall,
|
||||
@NotNull TranslationContext context) {
|
||||
super(context);
|
||||
this.qualifier = qualifier;
|
||||
this.propertyDescriptor = descriptor.getOriginal();
|
||||
this.resolvedCall = resolvedCall;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsExpression translateAsGet() {
|
||||
//TODO: check for duplication
|
||||
PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
|
||||
assert getter != null : "Getter for kotlin properties should bot be null.";
|
||||
return callBuilderForAccessor()
|
||||
.descriptor(getter)
|
||||
.translate();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsExpression translateAsSet(@NotNull JsExpression toSetTo) {
|
||||
//TODO: check for duplication
|
||||
PropertySetterDescriptor setter = propertyDescriptor.getSetter();
|
||||
assert setter != null : "Getter for kotlin properties should bot be null.";
|
||||
return callBuilderForAccessor()
|
||||
.args(toSetTo)
|
||||
.descriptor(setter)
|
||||
.translate();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private CallBuilder callBuilderForAccessor() {
|
||||
return CallBuilder.build(context())
|
||||
.receiver(qualifier)
|
||||
.resolvedCall(resolvedCall)
|
||||
.type(getCallType());
|
||||
}
|
||||
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.reference;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.backend.js.ast.JsName;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
import org.jetbrains.k2js.translate.utils.TranslationUtils;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.getExpectedThisDescriptor;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
* <p/>
|
||||
* For native apis that use .property notation for access.
|
||||
*/
|
||||
public final class NativePropertyAccessTranslator extends PropertyAccessTranslator {
|
||||
|
||||
|
||||
@Nullable
|
||||
private final JsExpression qualifier;
|
||||
@NotNull
|
||||
private final PropertyDescriptor propertyDescriptor;
|
||||
|
||||
/*package*/
|
||||
NativePropertyAccessTranslator(@NotNull PropertyDescriptor descriptor,
|
||||
@Nullable JsExpression qualifier,
|
||||
@NotNull TranslationContext context) {
|
||||
super(context);
|
||||
this.qualifier = qualifier;
|
||||
this.propertyDescriptor = descriptor.getOriginal();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsExpression translateAsGet() {
|
||||
JsName nativePropertyName = context().getNameForDescriptor(propertyDescriptor);
|
||||
JsExpression realQualifier = getQualifier();
|
||||
if (realQualifier != null) {
|
||||
return AstUtil.qualified(nativePropertyName, realQualifier);
|
||||
} else {
|
||||
return nativePropertyName.makeRef();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsExpression translateAsSet(@NotNull JsExpression setTo) {
|
||||
return AstUtil.assignment(translateAsGet(), setTo);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public JsExpression getQualifier() {
|
||||
if (qualifier != null) {
|
||||
return qualifier;
|
||||
}
|
||||
assert !propertyDescriptor.getReceiverParameter().exists() : "Cant have native extension properties.";
|
||||
DeclarationDescriptor expectedThisDescriptor = getExpectedThisDescriptor(propertyDescriptor);
|
||||
if (expectedThisDescriptor == null) {
|
||||
return null;
|
||||
}
|
||||
return TranslationUtils.getThisObject(context(), expectedThisDescriptor);
|
||||
}
|
||||
}
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.reference;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetQualifiedExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
|
||||
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.AnnotationsUtils.isNativeObject;
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForReferenceExpression;
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getResolvedCall;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getSelectorAsSimpleName;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.isBackingFieldReference;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public abstract class PropertyAccessTranslator extends AccessTranslator {
|
||||
|
||||
@NotNull
|
||||
public static PropertyAccessTranslator newInstance(@NotNull PropertyDescriptor descriptor,
|
||||
@NotNull ResolvedCall<?> resolvedCall,
|
||||
@NotNull TranslationContext context) {
|
||||
if (isNativeObject(descriptor)) {
|
||||
return new NativePropertyAccessTranslator(descriptor, /*qualifier = */ null, context);
|
||||
} else {
|
||||
return new KotlinPropertyAccessTranslator(descriptor, /*qualifier = */ null, resolvedCall, context);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static PropertyAccessTranslator newInstance(@NotNull JetSimpleNameExpression expression,
|
||||
@Nullable JsExpression qualifier,
|
||||
@NotNull CallType callType,
|
||||
@NotNull TranslationContext context) {
|
||||
PropertyAccessTranslator result;
|
||||
PropertyDescriptor propertyDescriptor = getPropertyDescriptor(expression, context);
|
||||
if (isNativeObject(propertyDescriptor) || isBackingFieldReference(expression)) {
|
||||
result = new NativePropertyAccessTranslator(propertyDescriptor, qualifier, context);
|
||||
} else {
|
||||
ResolvedCall<?> resolvedCall = getResolvedCall(context.bindingContext(), expression);
|
||||
result = new KotlinPropertyAccessTranslator(propertyDescriptor, qualifier, resolvedCall, context);
|
||||
}
|
||||
result.setCallType(callType);
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
/*package*/ static PropertyDescriptor getPropertyDescriptor(@NotNull JetSimpleNameExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
DeclarationDescriptor descriptor =
|
||||
getDescriptorForReferenceExpression(context.bindingContext(), expression);
|
||||
assert descriptor instanceof PropertyDescriptor : "Must be a property descriptor.";
|
||||
return (PropertyDescriptor) descriptor;
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
/*package*/
|
||||
static JsExpression translateAsPropertyGetterCall(@NotNull PropertyDescriptor descriptor,
|
||||
@NotNull ResolvedCall<?> resolvedCall,
|
||||
@NotNull TranslationContext context) {
|
||||
return (newInstance(descriptor, resolvedCall, context))
|
||||
.translateAsGet();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression translateAsPropertyGetterCall(@NotNull JetSimpleNameExpression expression,
|
||||
@Nullable JsExpression qualifier,
|
||||
@NotNull CallType callType,
|
||||
@NotNull TranslationContext context) {
|
||||
return (newInstance(expression, qualifier, callType, context))
|
||||
.translateAsGet();
|
||||
}
|
||||
|
||||
|
||||
public static boolean canBePropertyGetterCall(@NotNull JetQualifiedExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
JetSimpleNameExpression selector = getSelectorAsSimpleName(expression);
|
||||
assert selector != null : "Only names are allowed after the dot";
|
||||
return canBePropertyGetterCall(selector, context);
|
||||
}
|
||||
|
||||
public static boolean canBePropertyGetterCall(@NotNull JetSimpleNameExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return (getDescriptorForReferenceExpression
|
||||
(context.bindingContext(), expression) instanceof PropertyDescriptor);
|
||||
}
|
||||
|
||||
public static boolean canBePropertyGetterCall(@NotNull JetExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
if (expression instanceof JetQualifiedExpression) {
|
||||
return canBePropertyGetterCall((JetQualifiedExpression) expression, context);
|
||||
}
|
||||
if (expression instanceof JetSimpleNameExpression) {
|
||||
return canBePropertyGetterCall((JetSimpleNameExpression) expression, context);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean canBePropertyAccess(@NotNull JetExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return canBePropertyGetterCall(expression, context);
|
||||
}
|
||||
|
||||
//TODO: we use normal by default but may cause bugs
|
||||
private /*var*/ CallType callType = CallType.NORMAL;
|
||||
|
||||
protected PropertyAccessTranslator(@NotNull TranslationContext context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public void setCallType(@NotNull CallType callType) {
|
||||
this.callType = callType;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected CallType getCallType() {
|
||||
assert callType != null : "CallType not set";
|
||||
return callType;
|
||||
}
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.reference;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetCallExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetQualifiedExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
|
||||
import static org.jetbrains.k2js.translate.general.Translation.translateAsExpression;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getNotNullSimpleNameSelector;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getSelector;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class QualifiedExpressionTranslator {
|
||||
|
||||
private QualifiedExpressionTranslator() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static AccessTranslator getAccessTranslator(@NotNull JetQualifiedExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
|
||||
JsExpression receiver = translateReceiver(expression, context);
|
||||
PropertyAccessTranslator result =
|
||||
PropertyAccessTranslator.newInstance(getNotNullSimpleNameSelector(expression), receiver,
|
||||
CallType.getCallTypeForQualifiedExpression(expression), context);
|
||||
result.setCallType(CallType.getCallTypeForQualifiedExpression(expression));
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression translateQualifiedExpression(@NotNull JetQualifiedExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
JsExpression receiver = translateReceiver(expression, context);
|
||||
JetExpression selector = getSelector(expression);
|
||||
CallType callType = CallType.getCallTypeForQualifiedExpression(expression);
|
||||
return dispatchToCorrectTranslator(receiver, selector, callType, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static JsExpression dispatchToCorrectTranslator(@NotNull JsExpression receiver,
|
||||
@NotNull JetExpression selector,
|
||||
@NotNull CallType callType,
|
||||
@NotNull TranslationContext context) {
|
||||
if (PropertyAccessTranslator.canBePropertyGetterCall(selector, context)) {
|
||||
assert selector instanceof JetSimpleNameExpression : "Selectors for properties must be simple names.";
|
||||
return PropertyAccessTranslator.translateAsPropertyGetterCall
|
||||
((JetSimpleNameExpression) selector, receiver, callType, context);
|
||||
}
|
||||
if (selector instanceof JetCallExpression) {
|
||||
return CallExpressionTranslator.translate((JetCallExpression) selector, receiver, callType, context);
|
||||
}
|
||||
throw new AssertionError("Unexpected qualified expression");
|
||||
}
|
||||
|
||||
//TODO: if has duplications
|
||||
@NotNull
|
||||
private static JsExpression translateReceiver(@NotNull JetQualifiedExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return translateAsExpression(expression.getReceiverExpression(), context);
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.reference;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.backend.js.ast.JsNameRef;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class ReferenceAccessTranslator extends AccessTranslator {
|
||||
|
||||
@NotNull
|
||||
/*package*/ static ReferenceAccessTranslator newInstance(@NotNull JetSimpleNameExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
return new ReferenceAccessTranslator(expression, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final JetSimpleNameExpression expression;
|
||||
|
||||
private ReferenceAccessTranslator(@NotNull JetSimpleNameExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
super(context);
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsExpression translateAsGet() {
|
||||
//TODO: consider evaluating only once
|
||||
return ReferenceTranslator.translateSimpleName(expression, context());
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JsExpression translateAsSet(@NotNull JsExpression toSetTo) {
|
||||
//TODO: consider evaluating only once
|
||||
JsExpression reference = ReferenceTranslator.translateSimpleName(expression, context());
|
||||
assert reference instanceof JsNameRef;
|
||||
return AstUtil.newAssignment((JsNameRef) reference, toSetTo);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.reference;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.backend.js.ast.JsName;
|
||||
import com.google.dart.compiler.util.AstUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
|
||||
import org.jetbrains.k2js.translate.context.TranslationContext;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getDescriptorForReferenceExpression;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class ReferenceTranslator {
|
||||
|
||||
@NotNull
|
||||
public static JsExpression translateSimpleName(@NotNull JetSimpleNameExpression expression,
|
||||
@NotNull TranslationContext context) {
|
||||
if (PropertyAccessTranslator.canBePropertyGetterCall(expression, context)) {
|
||||
return PropertyAccessTranslator.translateAsPropertyGetterCall(expression, null, CallType.NORMAL, context);
|
||||
}
|
||||
DeclarationDescriptor referencedDescriptor =
|
||||
getDescriptorForReferenceExpression(context.bindingContext(), expression);
|
||||
return translateAsLocalNameReference(referencedDescriptor, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression translateAsFQReference(@NotNull DeclarationDescriptor referencedDescriptor,
|
||||
@NotNull TranslationContext context) {
|
||||
JsExpression qualifier = context.getQualifierForDescriptor(referencedDescriptor);
|
||||
if (qualifier == null) {
|
||||
return translateAsLocalNameReference(referencedDescriptor, context);
|
||||
}
|
||||
JsName referencedName = context.getNameForDescriptor(referencedDescriptor);
|
||||
return AstUtil.qualified(referencedName, qualifier);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression translateAsLocalNameReference(@NotNull DeclarationDescriptor referencedDescriptor,
|
||||
@NotNull TranslationContext context) {
|
||||
JsName referencedName = context.getNameForDescriptor(referencedDescriptor);
|
||||
return referencedName.makeRef();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.utils;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.getContainingClass;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class AnnotationsUtils {
|
||||
|
||||
@NotNull
|
||||
public static final String NATIVE_ANNOTATION_FQNAME = "js.native";
|
||||
@NotNull
|
||||
public static final String LIBRARY_ANNOTATION_FQNAME = "js.library";
|
||||
|
||||
private AnnotationsUtils() {
|
||||
}
|
||||
|
||||
//TODO: make public, use when necessary
|
||||
private static boolean hasAnnotation(@NotNull DeclarationDescriptor descriptor,
|
||||
@NotNull String annotationFQNAme) {
|
||||
return getAnnotationByName(descriptor, annotationFQNAme) != null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getAnnotationStringParameter(@NotNull DeclarationDescriptor declarationDescriptor,
|
||||
@NotNull String annotationFQName) {
|
||||
AnnotationDescriptor annotationDescriptor =
|
||||
getAnnotationByName(declarationDescriptor, annotationFQName);
|
||||
assert annotationDescriptor != null;
|
||||
//TODO: this is a quick fix for unsupported default args problem
|
||||
if (annotationDescriptor.getValueArguments().isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
CompileTimeConstant<?> constant = annotationDescriptor.getValueArguments().iterator().next();
|
||||
//TODO: this is a quick fix for unsupported default args problem
|
||||
if (constant == null) {
|
||||
return "";
|
||||
}
|
||||
Object value = constant.getValue();
|
||||
assert value instanceof String : "Native function annotation should have one String parameter";
|
||||
return (String) value;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static AnnotationDescriptor getAnnotationByName(@NotNull DeclarationDescriptor descriptor,
|
||||
@NotNull String FQName) {
|
||||
for (AnnotationDescriptor annotationDescriptor : descriptor.getAnnotations()) {
|
||||
String annotationClassFQName = getAnnotationClassFQName(annotationDescriptor);
|
||||
if (annotationClassFQName.equals(FQName)) {
|
||||
return annotationDescriptor;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getAnnotationClassFQName(@NotNull AnnotationDescriptor annotationDescriptor) {
|
||||
DeclarationDescriptor annotationDeclaration =
|
||||
annotationDescriptor.getType().getConstructor().getDeclarationDescriptor();
|
||||
assert annotationDeclaration != null : "Annotation supposed to have a declaration";
|
||||
return DescriptorUtils.getFQName(annotationDeclaration);
|
||||
}
|
||||
|
||||
public static boolean isNativeObject(@NotNull DeclarationDescriptor descriptor) {
|
||||
return hasAnnotationOrInsideAnnotatedClass(descriptor, NATIVE_ANNOTATION_FQNAME);
|
||||
}
|
||||
|
||||
public static boolean isLibraryObject(@NotNull DeclarationDescriptor descriptor) {
|
||||
return hasAnnotationOrInsideAnnotatedClass(descriptor, LIBRARY_ANNOTATION_FQNAME);
|
||||
}
|
||||
|
||||
//TODO: the use of this method is splattered across the code which can be hard to track
|
||||
public static boolean isPredefinedObject(@NotNull DeclarationDescriptor descriptor) {
|
||||
return isLibraryObject(descriptor) || isNativeObject(descriptor);
|
||||
}
|
||||
|
||||
private static boolean hasAnnotationOrInsideAnnotatedClass(DeclarationDescriptor descriptor, String annotationFQName) {
|
||||
if (getAnnotationByName(descriptor, annotationFQName) != null) {
|
||||
return true;
|
||||
}
|
||||
ClassDescriptor containingClass = getContainingClass(descriptor);
|
||||
if (containingClass == null) {
|
||||
return false;
|
||||
}
|
||||
return (getAnnotationByName(containingClass, annotationFQName) != null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.utils;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.jet.lang.types.JetStandardClasses;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.*;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
* <p/>
|
||||
* This class contains some code related to BindingContext use. Intention is not to pollute other classes.
|
||||
* Every call to BindingContext.get() is supposed to be wrapped by this utility class.
|
||||
*/
|
||||
public final class BindingUtils {
|
||||
|
||||
private BindingUtils() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static private <E extends PsiElement, D extends DeclarationDescriptor>
|
||||
D getDescriptorForExpression(@NotNull BindingContext context, @NotNull E expression, Class<D> descriptorClass) {
|
||||
DeclarationDescriptor descriptor = context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, expression);
|
||||
assert descriptor != null;
|
||||
assert descriptorClass.isInstance(descriptor)
|
||||
: expression.toString() + " expected to have of type" + descriptorClass.toString();
|
||||
//noinspection unchecked
|
||||
return (D) descriptor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ClassDescriptor getClassDescriptor(@NotNull BindingContext context,
|
||||
@NotNull JetClassOrObject declaration) {
|
||||
return getDescriptorForExpression(context, declaration, ClassDescriptor.class);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static NamespaceDescriptor getNamespaceDescriptor(@NotNull BindingContext context,
|
||||
@NotNull JetFile declaration) {
|
||||
NamespaceDescriptor namespaceDescriptor =
|
||||
context.get(BindingContext.FQNAME_TO_NAMESPACE_DESCRIPTOR, JetPsiUtil.getFQName(declaration));
|
||||
assert namespaceDescriptor != null : "File should have a namespace descriptor.";
|
||||
return namespaceDescriptor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static FunctionDescriptor getFunctionDescriptor(@NotNull BindingContext context,
|
||||
@NotNull JetDeclarationWithBody declaration) {
|
||||
return getDescriptorForExpression(context, declaration, FunctionDescriptor.class);
|
||||
}
|
||||
|
||||
//TODO:
|
||||
@NotNull
|
||||
public static PropertyAccessorDescriptor getPropertyAccessorDescriptor(@NotNull BindingContext context,
|
||||
@NotNull JetPropertyAccessor declaration) {
|
||||
return getDescriptorForExpression(context, declaration, PropertyAccessorDescriptor.class);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static PropertyDescriptor getPropertyDescriptor(@NotNull BindingContext context,
|
||||
@NotNull JetProperty declaration) {
|
||||
return getDescriptorForExpression(context, declaration, PropertyDescriptor.class);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JetClass getClassForDescriptor(@NotNull BindingContext context,
|
||||
@NotNull ClassDescriptor descriptor) {
|
||||
PsiElement result = context.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor);
|
||||
assert result instanceof JetClass : "ClassDescriptor should have declaration of type JetClass";
|
||||
return (JetClass) result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<JetDeclaration> getDeclarationsForNamespace(@NotNull BindingContext bindingContext,
|
||||
@NotNull NamespaceDescriptor namespace) {
|
||||
List<JetDeclaration> declarations = new ArrayList<JetDeclaration>();
|
||||
for (DeclarationDescriptor descriptor : namespace.getMemberScope().getAllDescriptors()) {
|
||||
if (AnnotationsUtils.isPredefinedObject(descriptor)) {
|
||||
continue;
|
||||
}
|
||||
//TODO:
|
||||
if (descriptor instanceof NamespaceDescriptor) {
|
||||
continue;
|
||||
}
|
||||
JetDeclaration declaration = BindingUtils.getDeclarationForDescriptor(bindingContext, descriptor);
|
||||
if (declaration != null) {
|
||||
declarations.add(declaration);
|
||||
}
|
||||
}
|
||||
return declarations;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static JetDeclaration getDeclarationForDescriptor(@NotNull BindingContext context,
|
||||
@NotNull DeclarationDescriptor descriptor) {
|
||||
PsiElement result = context.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor);
|
||||
if (result == null) {
|
||||
//TODO: never get there
|
||||
return null;
|
||||
}
|
||||
assert result instanceof JetDeclaration : "Descriptor should correspond to an element.";
|
||||
return (JetDeclaration) result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static JetParameter getParameterForDescriptor(@NotNull BindingContext context,
|
||||
@NotNull ValueParameterDescriptor descriptor) {
|
||||
PsiElement result = context.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor);
|
||||
assert result instanceof JetParameter : "ValueParameterDescriptor should have corresponding JetParameter.";
|
||||
return (JetParameter) result;
|
||||
}
|
||||
|
||||
public static boolean hasAncestorClass(@NotNull BindingContext context, @NotNull JetClassOrObject classDeclaration) {
|
||||
ClassDescriptor classDescriptor = getClassDescriptor(context, classDeclaration);
|
||||
List<ClassDescriptor> superclassDescriptors = getSuperclassDescriptors(classDescriptor);
|
||||
return (DescriptorUtils.findAncestorClass(superclassDescriptors) != null);
|
||||
}
|
||||
|
||||
public static boolean isStatement(@NotNull BindingContext context, @NotNull JetExpression expression) {
|
||||
Boolean isStatement = context.get(BindingContext.STATEMENT, expression);
|
||||
assert isStatement != null : "Invalid behaviour of get(BindingContext.STATEMENT)";
|
||||
return isStatement;
|
||||
// return IsStatement.isStatement(expression);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JetType getTypeByReference(@NotNull BindingContext context,
|
||||
@NotNull JetTypeReference typeReference) {
|
||||
JetType result = context.get(BindingContext.TYPE, typeReference);
|
||||
assert result != null : "TypeReference should reference a type";
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ClassDescriptor getClassDescriptorForTypeReference(@NotNull BindingContext context,
|
||||
@NotNull JetTypeReference typeReference) {
|
||||
return getClassDescriptorForType(getTypeByReference(context, typeReference));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PropertyDescriptor getPropertyDescriptorForConstructorParameter(@NotNull BindingContext context,
|
||||
@NotNull JetParameter parameter) {
|
||||
return context.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static JetProperty getPropertyForDescriptor(@NotNull BindingContext context,
|
||||
@NotNull PropertyDescriptor property) {
|
||||
PsiElement result = context.get(BindingContext.DESCRIPTOR_TO_DECLARATION, property);
|
||||
if (!(result instanceof JetProperty)) {
|
||||
return null;
|
||||
}
|
||||
return (JetProperty) result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static DeclarationDescriptor getDescriptorForReferenceExpression(@NotNull BindingContext context,
|
||||
@NotNull JetReferenceExpression reference) {
|
||||
DeclarationDescriptor referencedDescriptor = getNullableDescriptorForReferenceExpression(context, reference);
|
||||
assert referencedDescriptor != null : "Reference expression must reference a descriptor.";
|
||||
return referencedDescriptor;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static DeclarationDescriptor getNullableDescriptorForReferenceExpression(@NotNull BindingContext context,
|
||||
@NotNull JetReferenceExpression reference) {
|
||||
DeclarationDescriptor referencedDescriptor = context.get(BindingContext.REFERENCE_TARGET, reference);
|
||||
if (isVariableAsFunction(referencedDescriptor)) {
|
||||
assert referencedDescriptor != null;
|
||||
return getVariableDescriptorForVariableAsFunction((VariableAsFunctionDescriptor) referencedDescriptor);
|
||||
}
|
||||
return referencedDescriptor;
|
||||
}
|
||||
|
||||
public static boolean isNotAny(@NotNull DeclarationDescriptor superClassDescriptor) {
|
||||
return !superClassDescriptor.equals(JetStandardClasses.getAny());
|
||||
}
|
||||
|
||||
|
||||
//TODO: check where we use there, suspicious
|
||||
public static boolean isOwnedByNamespace(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (descriptor instanceof ConstructorDescriptor) {
|
||||
DeclarationDescriptor classDescriptor = descriptor.getContainingDeclaration();
|
||||
assert classDescriptor != null;
|
||||
return isOwnedByNamespace(classDescriptor);
|
||||
}
|
||||
return (descriptor.getContainingDeclaration() instanceof NamespaceDescriptor);
|
||||
}
|
||||
|
||||
public static boolean isOwnedByClass(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (descriptor instanceof ConstructorDescriptor) {
|
||||
DeclarationDescriptor classDescriptor = descriptor.getContainingDeclaration();
|
||||
assert classDescriptor != null;
|
||||
return isOwnedByClass(classDescriptor);
|
||||
}
|
||||
return (descriptor.getContainingDeclaration() instanceof ClassDescriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ResolvedCall<?> getResolvedCall(@NotNull BindingContext context,
|
||||
@NotNull JetExpression expression) {
|
||||
ResolvedCall<? extends CallableDescriptor> resolvedCall = context.get(BindingContext.RESOLVED_CALL, expression);
|
||||
assert resolvedCall != null : "Must resolve to a call.";
|
||||
return resolvedCall;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ResolvedCall<?> getResolvedCallForCallExpression(@NotNull BindingContext context,
|
||||
@NotNull JetCallExpression expression) {
|
||||
JetExpression calleeExpression = PsiUtils.getCallee(expression);
|
||||
return getResolvedCall(context, calleeExpression);
|
||||
}
|
||||
|
||||
public static boolean isVariableReassignment(@NotNull BindingContext context, @NotNull JetExpression expression) {
|
||||
Boolean result = context.get(BindingContext.VARIABLE_REASSIGNMENT, expression);
|
||||
assert result != null;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
public static FunctionDescriptor getFunctionDescriptorForOperationExpression(@NotNull BindingContext context,
|
||||
@NotNull JetOperationExpression expression) {
|
||||
DeclarationDescriptor descriptorForReferenceExpression = getNullableDescriptorForReferenceExpression
|
||||
(context, expression.getOperationReference());
|
||||
|
||||
if (descriptorForReferenceExpression == null) return null;
|
||||
|
||||
assert descriptorForReferenceExpression instanceof FunctionDescriptor
|
||||
: "Operation should resolve to function descriptor.";
|
||||
return (FunctionDescriptor) descriptorForReferenceExpression;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static DeclarationDescriptor getDescriptorForElement(@NotNull BindingContext context,
|
||||
@NotNull PsiElement element) {
|
||||
DeclarationDescriptor descriptor = context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element);
|
||||
assert descriptor != null : element + " doesn't have a descriptor.";
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Object getCompileTimeValue(@NotNull BindingContext context, @NotNull JetExpression expression) {
|
||||
CompileTimeConstant<?> compileTimeValue = context.get(BindingContext.COMPILE_TIME_VALUE, expression);
|
||||
if (compileTimeValue != null) {
|
||||
return compileTimeValue.getValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JetExpression getDefaultArgument(@NotNull BindingContext context,
|
||||
@NotNull ValueParameterDescriptor parameterDescriptor) {
|
||||
assert parameterDescriptor.hasDefaultValue() : "Unsupplied parameter must have default value.";
|
||||
JetParameter psiParameter = getParameterForDescriptor(context, parameterDescriptor);
|
||||
JetExpression defaultValue = psiParameter.getDefaultValue();
|
||||
assert defaultValue != null : "No default value found in PSI.";
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static FunctionDescriptor getIteratorFunction(@NotNull BindingContext context,
|
||||
@NotNull JetExpression rangeExpression) {
|
||||
FunctionDescriptor functionDescriptor = context.get(BindingContext.LOOP_RANGE_ITERATOR, rangeExpression);
|
||||
assert functionDescriptor != null : "Range expression must have a descriptor for iterator function.";
|
||||
return functionDescriptor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static FunctionDescriptor getNextFunction(@NotNull BindingContext context,
|
||||
@NotNull JetExpression rangeExpression) {
|
||||
FunctionDescriptor functionDescriptor = context.get(BindingContext.LOOP_RANGE_NEXT, rangeExpression);
|
||||
assert functionDescriptor != null : "Range expression must have a descriptor for next function.";
|
||||
return functionDescriptor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static CallableDescriptor getHasNextCallable(@NotNull BindingContext context,
|
||||
@NotNull JetExpression rangeExpression) {
|
||||
CallableDescriptor hasNextDescriptor = context.get(BindingContext.LOOP_RANGE_HAS_NEXT, rangeExpression);
|
||||
assert hasNextDescriptor != null : "Range expression must have a descriptor for hasNext function or property.";
|
||||
return hasNextDescriptor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static PropertyDescriptor getPropertyDescriptorForObjectDeclaration(@NotNull BindingContext context,
|
||||
@NotNull JetObjectDeclarationName name) {
|
||||
PropertyDescriptor propertyDescriptor = context.get(BindingContext.OBJECT_DECLARATION, name);
|
||||
assert propertyDescriptor != null;
|
||||
return propertyDescriptor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Set<NamespaceDescriptor> getAllNonNativeNamespaceDescriptors(@NotNull BindingContext context,
|
||||
@NotNull List<JetFile> files) {
|
||||
Set<NamespaceDescriptor> descriptorSet = Sets.newHashSet();
|
||||
for (JetFile file : files) {
|
||||
NamespaceDescriptor namespaceDescriptor = getNamespaceDescriptor(context, file);
|
||||
if (!AnnotationsUtils.isPredefinedObject(namespaceDescriptor)) {
|
||||
descriptorSet.add(namespaceDescriptor);
|
||||
}
|
||||
}
|
||||
return descriptorSet;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JetType getTypeForExpression(@NotNull BindingContext context,
|
||||
@NotNull JetExpression expression) {
|
||||
JetType type = context.get(BindingContext.EXPRESSION_TYPE, expression);
|
||||
assert type != null;
|
||||
return type;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.utils;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetClass;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.DescriptorUtils.getSuperclassDescriptors;
|
||||
|
||||
|
||||
//TODO: can optimise using less dumb implementation
|
||||
//TODO: pass list of descriptors here, not the list of jet classes
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class ClassSorter {
|
||||
|
||||
@NotNull
|
||||
private final List<ClassDescriptor> descriptorList;
|
||||
@NotNull
|
||||
private final List<ClassDescriptor> classesWithNoAncestors;
|
||||
@NotNull
|
||||
private final Map<ClassDescriptor, Integer> classWasInheritedCount = new HashMap<ClassDescriptor, Integer>();
|
||||
@NotNull
|
||||
private final BindingContext bindingContext;
|
||||
|
||||
@NotNull
|
||||
public static List<JetClass> sortUsingInheritanceOrder(@NotNull List<JetClass> original,
|
||||
@NotNull BindingContext bindingContext) {
|
||||
ClassSorter sorter = new ClassSorter(original, bindingContext);
|
||||
return sorter.sortUsingInheritanceOrder();
|
||||
}
|
||||
|
||||
private ClassSorter(@NotNull List<JetClass> original, @NotNull BindingContext bindingContext) {
|
||||
this.bindingContext = bindingContext;
|
||||
this.descriptorList = getDescriptorList(original);
|
||||
this.classesWithNoAncestors = new ArrayList<ClassDescriptor>(descriptorList);
|
||||
setInitialCount();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<JetClass> sortUsingInheritanceOrder() {
|
||||
List<JetClass> sortedClasses = new ArrayList<JetClass>();
|
||||
while (!classesWithNoAncestors.isEmpty()) {
|
||||
ClassDescriptor classDescriptor = getNextClass();
|
||||
sortedClasses.add(BindingUtils.getClassForDescriptor(bindingContext, classDescriptor));
|
||||
}
|
||||
assert sortedClasses.size() == descriptorList.size();
|
||||
return sortedClasses;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private ClassDescriptor getNextClass() {
|
||||
ClassDescriptor result = popFromList();
|
||||
decreaseCountForDerivedClasses(result);
|
||||
classWasInheritedCount.remove(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void decreaseCountForDerivedClasses(@NotNull ClassDescriptor result) {
|
||||
for (ClassDescriptor derived : descriptorList) {
|
||||
if (isDerivedClass(result, derived)) {
|
||||
decreaseCountForDerivedClass(derived);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void decreaseCountForDerivedClass(@NotNull ClassDescriptor derived) {
|
||||
Integer timesInherited = classWasInheritedCount.get(derived);
|
||||
assert timesInherited != null;
|
||||
assert timesInherited > 0;
|
||||
int newCount = timesInherited - 1;
|
||||
classWasInheritedCount.put(derived, newCount);
|
||||
if (newCount == 0) {
|
||||
classesWithNoAncestors.add(derived);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isDerivedClass(@NotNull ClassDescriptor ancestor, @NotNull ClassDescriptor derived) {
|
||||
return (getSuperclassDescriptors(derived).contains(ancestor));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private ClassDescriptor popFromList() {
|
||||
assert !classesWithNoAncestors.isEmpty();
|
||||
ClassDescriptor result = classesWithNoAncestors.get(classesWithNoAncestors.size() - 1);
|
||||
ClassDescriptor removed = classesWithNoAncestors.remove(classesWithNoAncestors.size() - 1);
|
||||
assert removed != null;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
private List<ClassDescriptor> getDescriptorList(@NotNull List<JetClass> classesToSort) {
|
||||
List<ClassDescriptor> descriptorList = new ArrayList<ClassDescriptor>();
|
||||
for (JetClass jetClass : classesToSort) {
|
||||
descriptorList.add(BindingUtils.getClassDescriptor(bindingContext, jetClass));
|
||||
}
|
||||
return descriptorList;
|
||||
}
|
||||
|
||||
private void setInitialCount() {
|
||||
for (ClassDescriptor descriptor : descriptorList) {
|
||||
List<ClassDescriptor> superclasses = getSuperclassDescriptors(descriptor);
|
||||
int count = 0;
|
||||
for (ClassDescriptor superclassDescriptor : superclasses) {
|
||||
if (descriptorList.contains(superclassDescriptor)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
classWasInheritedCount.put(descriptor, superclasses.size());
|
||||
if (count > 0) {
|
||||
boolean success = classesWithNoAncestors.remove(descriptor);
|
||||
assert success;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright 2000-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.translate.utils;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
|
||||
import org.jetbrains.k2js.translate.context.Namer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.isNotAny;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class DescriptorUtils {
|
||||
|
||||
private DescriptorUtils() {
|
||||
}
|
||||
|
||||
private static int valueParametersCount(@NotNull FunctionDescriptor functionDescriptor) {
|
||||
return functionDescriptor.getValueParameters().size();
|
||||
}
|
||||
|
||||
public static boolean hasParameters(@NotNull FunctionDescriptor functionDescriptor) {
|
||||
return (valueParametersCount(functionDescriptor) > 0);
|
||||
}
|
||||
|
||||
public static boolean isEquals(@NotNull FunctionDescriptor functionDescriptor) {
|
||||
return (functionDescriptor.getName().equals(OperatorConventions.EQUALS));
|
||||
}
|
||||
|
||||
public static boolean isCompareTo(@NotNull FunctionDescriptor functionDescriptor) {
|
||||
return (functionDescriptor.getName().equals(OperatorConventions.COMPARE_TO));
|
||||
}
|
||||
|
||||
public static boolean isConstructorDescriptor(@NotNull CallableDescriptor descriptor) {
|
||||
return (descriptor instanceof ConstructorDescriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static FunctionDescriptor getFunctionByName(@NotNull JetScope scope,
|
||||
@NotNull String name) {
|
||||
Set<FunctionDescriptor> functionDescriptors = scope.getFunctions(name);
|
||||
assert functionDescriptors.size() == 1 :
|
||||
"In scope " + scope + " supposed to be exactly one " + name + " function.\n" +
|
||||
"Found: " + functionDescriptors.size();
|
||||
//noinspection LoopStatementThatDoesntLoop
|
||||
for (FunctionDescriptor descriptor : functionDescriptors) {
|
||||
return descriptor;
|
||||
}
|
||||
throw new AssertionError("In scope " + scope
|
||||
+ " supposed to be exactly one " + name + " function.");
|
||||
}
|
||||
|
||||
//TODO: some stange stuff happening to this method
|
||||
@NotNull
|
||||
public static PropertyDescriptor getPropertyByName(@NotNull JetScope scope,
|
||||
@NotNull String name) {
|
||||
VariableDescriptor variable = scope.getLocalVariable(name);
|
||||
if (variable == null) {
|
||||
variable = scope.getPropertyByFieldReference("$" + name);
|
||||
}
|
||||
Set<VariableDescriptor> variables = scope.getProperties(name);
|
||||
assert variables.size() == 1 : "Actual size: " + variables.size();
|
||||
variable = variables.iterator().next();
|
||||
PropertyDescriptor descriptor = (PropertyDescriptor) variable;
|
||||
assert descriptor != null : "Must have a descriptor.";
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ClassDescriptor findAncestorClass(@NotNull List<ClassDescriptor> superclassDescriptors) {
|
||||
for (ClassDescriptor descriptor : superclassDescriptors) {
|
||||
if (descriptor.getKind() == ClassKind.CLASS) {
|
||||
return descriptor;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<ClassDescriptor> getSuperclassDescriptors(@NotNull ClassDescriptor classDescriptor) {
|
||||
Collection<? extends JetType> superclassTypes = classDescriptor.getTypeConstructor().getSupertypes();
|
||||
List<ClassDescriptor> superClassDescriptors = new ArrayList<ClassDescriptor>();
|
||||
for (JetType type : superclassTypes) {
|
||||
ClassDescriptor result = getClassDescriptorForType(type);
|
||||
if (isNotAny(result)) {
|
||||
superClassDescriptors.add(result);
|
||||
}
|
||||
}
|
||||
return superClassDescriptors;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ClassDescriptor getSuperclass(@NotNull ClassDescriptor classDescriptor) {
|
||||
return findAncestorClass(getSuperclassDescriptors(classDescriptor));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ClassDescriptor getClassDescriptorForType(@NotNull JetType type) {
|
||||
DeclarationDescriptor superClassDescriptor =
|
||||
type.getConstructor().getDeclarationDescriptor();
|
||||
assert superClassDescriptor instanceof ClassDescriptor
|
||||
: "Superclass descriptor of a type should be of type ClassDescriptor";
|
||||
return (ClassDescriptor) superClassDescriptor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static VariableDescriptor getVariableDescriptorForVariableAsFunction
|
||||
(@NotNull VariableAsFunctionDescriptor descriptor) {
|
||||
VariableDescriptor functionVariable = descriptor.getVariableDescriptor();
|
||||
assert functionVariable != null;
|
||||
return functionVariable;
|
||||
}
|
||||
|
||||
|
||||
public static boolean isVariableAsFunction(@Nullable DeclarationDescriptor referencedDescriptor) {
|
||||
return referencedDescriptor instanceof VariableAsFunctionDescriptor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static DeclarationDescriptor getContainingDeclaration(@NotNull DeclarationDescriptor descriptor) {
|
||||
DeclarationDescriptor containing = descriptor.getContainingDeclaration();
|
||||
assert containing != null : "Should be called on objects that have containing declaration.";
|
||||
return containing;
|
||||
}
|
||||
|
||||
public static boolean isExtensionFunction(@NotNull CallableDescriptor functionDescriptor) {
|
||||
return (functionDescriptor.getReceiverParameter().exists());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getNameForNamespace(@NotNull NamespaceDescriptor descriptor) {
|
||||
String name = descriptor.getName();
|
||||
if (name.equals("")) {
|
||||
return Namer.getAnonymousNamespaceName();
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
//TODO: why callable descriptor
|
||||
@Nullable
|
||||
public static DeclarationDescriptor getExpectedThisDescriptor(@NotNull CallableDescriptor callableDescriptor) {
|
||||
ReceiverDescriptor expectedThisObject = callableDescriptor.getExpectedThisObject();
|
||||
if (!expectedThisObject.exists()) {
|
||||
return null;
|
||||
}
|
||||
return getDeclarationDescriptorForReceiver(expectedThisObject);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static DeclarationDescriptor getDeclarationDescriptorForReceiver
|
||||
(@NotNull ReceiverDescriptor receiverParameter) {
|
||||
DeclarationDescriptor declarationDescriptor =
|
||||
receiverParameter.getType().getConstructor().getDeclarationDescriptor();
|
||||
//TODO: WHY assert?
|
||||
assert declarationDescriptor != null;
|
||||
return declarationDescriptor.getOriginal();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static DeclarationDescriptor getExpectedReceiverDescriptor(@NotNull CallableDescriptor callableDescriptor) {
|
||||
ReceiverDescriptor receiverParameter = callableDescriptor.getReceiverParameter();
|
||||
if (!receiverParameter.exists()) {
|
||||
return null;
|
||||
}
|
||||
return getDeclarationDescriptorForReceiver(receiverParameter);
|
||||
}
|
||||
|
||||
//TODO: maybe we have similar routine
|
||||
@Nullable
|
||||
public static ClassDescriptor getContainingClass(@NotNull DeclarationDescriptor descriptor) {
|
||||
DeclarationDescriptor containing = descriptor.getContainingDeclaration();
|
||||
while (containing != null) {
|
||||
if (containing instanceof ClassDescriptor) {
|
||||
return (ClassDescriptor) containing;
|
||||
}
|
||||
containing = containing.getContainingDeclaration();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<ClassDescriptor> getAllClassesDefinedInNamespace(@NotNull NamespaceDescriptor namespaceDescriptor) {
|
||||
List<ClassDescriptor> classDescriptors = Lists.newArrayList();
|
||||
for (DeclarationDescriptor descriptor : namespaceDescriptor.getMemberScope().getAllDescriptors()) {
|
||||
if (AnnotationsUtils.isPredefinedObject(descriptor)) {
|
||||
continue;
|
||||
}
|
||||
if (descriptor instanceof ClassDescriptor) {
|
||||
classDescriptors.add((ClassDescriptor) descriptor);
|
||||
}
|
||||
}
|
||||
return classDescriptors;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user