First stab at inline functions.
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2010-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.k2js.test.semantics;
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.k2js.test.SingleFileTranslationTest;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class InlineTest extends SingleFileTranslationTest {
|
||||
public InlineTest() {
|
||||
super("inline/");
|
||||
}
|
||||
|
||||
public void testFunctionWithoutParameters() throws Exception {
|
||||
String filename = "functionWithoutParameters.kt";
|
||||
checkFooBoxIsTrue(filename);
|
||||
String generatedJSFilePath = getOutputFilePath(filename);
|
||||
String outputFileText = FileUtil.loadFile(new File(generatedJSFilePath));
|
||||
assertTrue(countOccurrences(outputFileText, "myInlineFun") == 1);
|
||||
}
|
||||
|
||||
private static int countOccurrences(@NotNull String str, @NotNull String subStr) {
|
||||
int count = 0;
|
||||
String s = str;
|
||||
while (s.contains(subStr)) {
|
||||
s = s.replaceFirst(subStr, "");
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
@@ -79,6 +79,13 @@ public class AliasingContext {
|
||||
return newContext;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public AliasingContext withDescriptorsAliased(@NotNull Map<DeclarationDescriptor, JsName> aliases) {
|
||||
AliasingContext newContext = new AliasingContext(this);
|
||||
newContext.aliasesForDescriptors.putAll(aliases);
|
||||
return newContext;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private AliasingContext getParent() {
|
||||
assert parent != null;
|
||||
|
||||
@@ -93,6 +93,11 @@ public final class TranslationContext {
|
||||
return new TranslationContext(staticContext, dynamicContext, aliasingContext.withAliasesForExpressions(aliases));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public TranslationContext innerContextWithDescriptorsAliased(@NotNull Map<DeclarationDescriptor, JsName> aliases) {
|
||||
return new TranslationContext(staticContext, dynamicContext, aliasingContext.withDescriptorsAliased(aliases));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsBlock getBlockForDescriptor(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (descriptor instanceof CallableDescriptor) {
|
||||
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 2010-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.k2js.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.psi.ValueArgument;
|
||||
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 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;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public abstract class AbstractCallExpressionTranslator extends AbstractTranslator {
|
||||
|
||||
@NotNull
|
||||
protected final JetCallExpression expression;
|
||||
@NotNull
|
||||
protected final ResolvedCall<?> resolvedCall;
|
||||
@Nullable
|
||||
protected final JsExpression receiver;
|
||||
@NotNull
|
||||
protected final CallType callType;
|
||||
|
||||
protected AbstractCallExpressionTranslator(@NotNull JetCallExpression expression,
|
||||
@Nullable JsExpression receiver,
|
||||
@NotNull CallType type, @NotNull TranslationContext context) {
|
||||
super(context);
|
||||
this.expression = expression;
|
||||
this.resolvedCall = getResolvedCallForCallExpression(bindingContext(), expression);
|
||||
this.receiver = receiver;
|
||||
callType = type;
|
||||
}
|
||||
|
||||
abstract public boolean shouldWrapVarargInArray();
|
||||
|
||||
@NotNull
|
||||
protected List<JsExpression> translateSingleArgument(@NotNull ResolvedValueArgument actualArgument,
|
||||
@NotNull ValueParameterDescriptor parameterDescriptor) {
|
||||
List<ValueArgument> valueArguments = actualArgument.getArguments();
|
||||
if (actualArgument instanceof VarargValueArgument) {
|
||||
return translateVarargArgument(valueArguments);
|
||||
}
|
||||
if (actualArgument instanceof DefaultValueArgument) {
|
||||
JetExpression defaultArgument = getDefaultArgument(bindingContext(), parameterDescriptor);
|
||||
return Arrays.asList(Translation.translateAsExpression(defaultArgument, context()));
|
||||
}
|
||||
assert actualArgument instanceof ExpressionValueArgument;
|
||||
assert valueArguments.size() == 1;
|
||||
JetExpression argumentExpression = valueArguments.get(0).getArgumentExpression();
|
||||
assert argumentExpression != null;
|
||||
return Arrays.asList(Translation.translateAsExpression(argumentExpression, context()));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<JsExpression> translateVarargArgument(@NotNull List<ValueArgument> arguments) {
|
||||
List<JsExpression> translatedArgs = Lists.newArrayList();
|
||||
for (ValueArgument argument : arguments) {
|
||||
JetExpression argumentExpression = argument.getArgumentExpression();
|
||||
assert argumentExpression != null;
|
||||
translatedArgs.add(Translation.translateAsExpression(argumentExpression, context()));
|
||||
}
|
||||
if (shouldWrapVarargInArray()) {
|
||||
return wrapInArrayLiteral(translatedArgs);
|
||||
}
|
||||
return translatedArgs;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<JsExpression> wrapInArrayLiteral(@NotNull List<JsExpression> translatedArgs) {
|
||||
JsArrayLiteral argsWrappedInArray = new JsArrayLiteral();
|
||||
argsWrappedInArray.getExpressions().addAll(translatedArgs);
|
||||
return Arrays.<JsExpression>asList(argsWrappedInArray);
|
||||
}
|
||||
}
|
||||
+20
-63
@@ -16,8 +16,6 @@
|
||||
|
||||
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;
|
||||
@@ -27,61 +25,51 @@ import org.jetbrains.jet.lang.descriptors.VariableAsFunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetCallExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
|
||||
import org.jetbrains.jet.lang.psi.ValueArgument;
|
||||
import org.jetbrains.jet.lang.resolve.calls.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.ExpressionAsFunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.resolve.calls.ResolvedValueArgument;
|
||||
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 {
|
||||
public final class CallExpressionTranslator extends AbstractCallExpressionTranslator {
|
||||
|
||||
@NotNull
|
||||
public static JsExpression translate(@NotNull JetCallExpression expression,
|
||||
@Nullable JsExpression receiver,
|
||||
@NotNull CallType callType,
|
||||
@NotNull TranslationContext context) {
|
||||
return (new CallExpressionTranslator(expression, receiver, context)).translate(callType);
|
||||
if (InlinedCallExpressionTranslator.shouldBeInlined(expression, context)) {
|
||||
return InlinedCallExpressionTranslator.translate(expression, receiver, callType, context);
|
||||
}
|
||||
return (new CallExpressionTranslator(expression, receiver, callType, context)).translate();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private final JetCallExpression expression;
|
||||
@NotNull
|
||||
private final ResolvedCall<?> resolvedCall;
|
||||
private final boolean isNativeFunctionCall;
|
||||
@Nullable
|
||||
private final JsExpression receiver;
|
||||
|
||||
private CallExpressionTranslator(@NotNull JetCallExpression expression,
|
||||
@Nullable JsExpression receiver,
|
||||
@NotNull TranslationContext context) {
|
||||
super(context);
|
||||
this.expression = expression;
|
||||
this.resolvedCall = getResolvedCallForCallExpression(bindingContext(), expression);
|
||||
this.receiver = receiver;
|
||||
@NotNull CallType callType, @NotNull TranslationContext context) {
|
||||
super(expression, receiver, callType, context);
|
||||
this.isNativeFunctionCall = AnnotationsUtils.isNativeObject(resolvedCall.getCandidateDescriptor());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression translate(@NotNull CallType callType) {
|
||||
private JsExpression translate() {
|
||||
return CallBuilder.build(context())
|
||||
.receiver(receiver)
|
||||
.callee(getCalleeExpression())
|
||||
.args(translateArguments())
|
||||
.resolvedCall(resolvedCall)
|
||||
.type(callType)
|
||||
.translate();
|
||||
.receiver(receiver)
|
||||
.callee(getCalleeExpression())
|
||||
.args(translateArguments())
|
||||
.resolvedCall(resolvedCall)
|
||||
.type(callType)
|
||||
.translate();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -100,7 +88,7 @@ public final class CallExpressionTranslator extends AbstractTranslator {
|
||||
private JsExpression translateVariableAsFunction() {
|
||||
JetExpression callee = getCallee(expression);
|
||||
assert callee instanceof JetSimpleNameExpression;
|
||||
return ReferenceTranslator.getAccessTranslator((JetSimpleNameExpression) callee, receiver, context()).translateAsGet();
|
||||
return ReferenceTranslator.getAccessTranslator((JetSimpleNameExpression)callee, receiver, context()).translateAsGet();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -111,7 +99,6 @@ public final class CallExpressionTranslator extends AbstractTranslator {
|
||||
@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));
|
||||
@@ -119,38 +106,8 @@ public final class CallExpressionTranslator extends AbstractTranslator {
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<JsExpression> translateSingleArgument(@NotNull ResolvedValueArgument actualArgument,
|
||||
@NotNull ValueParameterDescriptor parameterDescriptor) {
|
||||
List<ValueArgument> valueArguments = actualArgument.getArguments();
|
||||
if (actualArgument instanceof VarargValueArgument) {
|
||||
return translateVarargArgument(valueArguments);
|
||||
}
|
||||
if (actualArgument instanceof DefaultValueArgument) {
|
||||
JetExpression defaultArgument = getDefaultArgument(bindingContext(), parameterDescriptor);
|
||||
return Arrays.asList(Translation.translateAsExpression(defaultArgument, context()));
|
||||
}
|
||||
assert actualArgument instanceof ExpressionValueArgument;
|
||||
assert valueArguments.size() == 1;
|
||||
return Arrays.asList(Translation.translateAsExpression(valueArguments.get(0).getArgumentExpression(), context()));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<JsExpression> translateVarargArgument(@NotNull List<ValueArgument> arguments) {
|
||||
List<JsExpression> translatedArgs = Lists.newArrayList();
|
||||
for (ValueArgument argument : arguments) {
|
||||
translatedArgs.add(Translation.translateAsExpression(argument.getArgumentExpression(), context()));
|
||||
}
|
||||
if (isNativeFunctionCall) {
|
||||
return translatedArgs;
|
||||
}
|
||||
return wrapInArrayLiteral(translatedArgs);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<JsExpression> wrapInArrayLiteral(@NotNull List<JsExpression> translatedArgs) {
|
||||
JsArrayLiteral argsWrappedInArray = new JsArrayLiteral();
|
||||
argsWrappedInArray.getExpressions().addAll(translatedArgs);
|
||||
return Arrays.<JsExpression>asList(argsWrappedInArray);
|
||||
@Override
|
||||
public boolean shouldWrapVarargInArray() {
|
||||
return !isNativeFunctionCall;
|
||||
}
|
||||
}
|
||||
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright 2010-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.k2js.translate.reference;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.backend.js.ast.JsName;
|
||||
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.descriptors.SimpleFunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetCallExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetFunction;
|
||||
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.calls.ResolvedValueArgument;
|
||||
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 java.util.Map;
|
||||
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getResolvedCallForCallExpression;
|
||||
|
||||
/**
|
||||
* @author Pavel Talanov
|
||||
*/
|
||||
public final class InlinedCallExpressionTranslator extends AbstractCallExpressionTranslator {
|
||||
|
||||
public static boolean shouldBeInlined(@NotNull JetCallExpression expression, @NotNull TranslationContext context) {
|
||||
ResolvedCall<?> resolvedCall = getResolvedCallForCallExpression(context.bindingContext(), expression);
|
||||
CallableDescriptor descriptor = resolvedCall.getCandidateDescriptor();
|
||||
if (descriptor instanceof SimpleFunctionDescriptor) {
|
||||
return ((SimpleFunctionDescriptor)descriptor).isInline();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JsExpression translate(@NotNull JetCallExpression expression,
|
||||
@Nullable JsExpression receiver,
|
||||
@NotNull CallType callType,
|
||||
@NotNull TranslationContext context) {
|
||||
return (new InlinedCallExpressionTranslator(expression, receiver, callType, context)).translate();
|
||||
}
|
||||
|
||||
private InlinedCallExpressionTranslator(@NotNull JetCallExpression expression, @Nullable JsExpression receiver,
|
||||
@NotNull CallType callType, @NotNull TranslationContext context) {
|
||||
super(expression, receiver, callType, context);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression translate() {
|
||||
TranslationContext contextWithAllParametersAliased = createContextWithAllParametersAliased();
|
||||
JetFunction function = BindingUtils.getFunctionForDescriptor(bindingContext(), getFunctionDescriptor());
|
||||
return Translation.translateAsExpression(function.getBodyExpression(), contextWithAllParametersAliased);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private SimpleFunctionDescriptor getFunctionDescriptor() {
|
||||
CallableDescriptor descriptor = resolvedCall.getCandidateDescriptor().getOriginal();
|
||||
assert descriptor instanceof SimpleFunctionDescriptor : "Inlined functions should have descriptor of type SimpleFunctionDescriptor";
|
||||
return (SimpleFunctionDescriptor)descriptor;
|
||||
}
|
||||
|
||||
private TranslationContext createContextWithAllParametersAliased() {
|
||||
Map<DeclarationDescriptor, JsName> aliases = Maps.newHashMap();
|
||||
for (ValueParameterDescriptor parameterDescriptor : resolvedCall.getResultingDescriptor().getValueParameters()) {
|
||||
ResolvedValueArgument actualArgument = resolvedCall.getValueArgumentsByIndex().get(parameterDescriptor.getIndex());
|
||||
JsExpression translatedArgument = translateArgument(parameterDescriptor, actualArgument);
|
||||
TemporaryVariable aliasForArgument = context().declareTemporary(translatedArgument);
|
||||
aliases.put(parameterDescriptor, aliasForArgument.name());
|
||||
context().addStatementToCurrentBlock(aliasForArgument.assignmentExpression().makeStmt());
|
||||
}
|
||||
return context().innerContextWithDescriptorsAliased(aliases);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression translateArgument(@NotNull ValueParameterDescriptor parameterDescriptor,
|
||||
@NotNull ResolvedValueArgument actualArgument) {
|
||||
List<JsExpression> translatedSingleArgument = translateSingleArgument(actualArgument, parameterDescriptor);
|
||||
assert translatedSingleArgument.size() == 1 : "We always wrap varargs in kotlin calls.";
|
||||
return translatedSingleArgument.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldWrapVarargInArray() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -93,6 +93,14 @@ public final class BindingUtils {
|
||||
return (JetClass)result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JetFunction getFunctionForDescriptor(@NotNull BindingContext context,
|
||||
@NotNull SimpleFunctionDescriptor descriptor) {
|
||||
PsiElement result = context.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor);
|
||||
assert result instanceof JetFunction : "SimpleFunctionDescriptor should have declaration of type JetFunction";
|
||||
return (JetFunction)result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<JetDeclaration> getDeclarationsForNamespace(@NotNull BindingContext bindingContext,
|
||||
@NotNull NamespaceDescriptor namespace) {
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package foo
|
||||
|
||||
fun box() = myInlineFun()
|
||||
|
||||
inline fun myInlineFun() = true
|
||||
Reference in New Issue
Block a user