initial changes

This commit is contained in:
pTalanov
2012-02-27 15:30:47 +04:00
parent e0cdbd6099
commit 8d6525f23f
396 changed files with 554 additions and 18555 deletions
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);
}
@@ -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;
}
}
@@ -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();
}
}
@@ -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;
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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());
}
}
@@ -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());
}
}
@@ -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());
}
}
@@ -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;
}
}
@@ -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();
}
}
@@ -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));
}
}
@@ -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());
}
}
@@ -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());
}
}
@@ -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);
}
}
}
@@ -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;
}
}
@@ -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);
}
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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;
}
}
@@ -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));
}
}
@@ -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);
}
}
@@ -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));
}
}
}
@@ -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;
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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;
}
}
@@ -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);
}
}
@@ -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);
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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);
}
@@ -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;
}
*/
}
@@ -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);
}
}
@@ -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());
}
}
@@ -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);
}
}
@@ -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;
}
}
@@ -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);
}
}
@@ -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;
}
}