JS backend: expand jsCode at translator

This commit is contained in:
Alexey Tsvetkov
2014-03-24 06:10:07 +04:00
parent 41af895caa
commit bc7afdf0b8
4 changed files with 101 additions and 17 deletions
+1
View File
@@ -14,5 +14,6 @@
<orderEntry type="module" module-name="js.dart-ast" exported="" /> <orderEntry type="module" module-name="js.dart-ast" exported="" />
<orderEntry type="module" module-name="js.frontend" exported="" /> <orderEntry type="module" module-name="js.frontend" exported="" />
<orderEntry type="module" module-name="js.inliner" exported="" /> <orderEntry type="module" module-name="js.inliner" exported="" />
<orderEntry type="module" module-name="js.parser" />
</component> </component>
</module> </module>
@@ -191,8 +191,12 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
if (shouldBeInlined(expression, context) && if (shouldBeInlined(expression, context) &&
BindingContextUtilPackage.isUsedAsExpression(expression, context.bindingContext())) { BindingContextUtilPackage.isUsedAsExpression(expression, context.bindingContext())) {
TemporaryVariable temporaryVariable = context.declareTemporary(null); TemporaryVariable temporaryVariable = context.declareTemporary(null);
JsExpression callResult = CallExpressionTranslator.translate(expression, null, context).source(expression);
context.addStatementToCurrentBlock(JsAstUtils.assignment(temporaryVariable.reference(), callResult).makeStmt()); JsNode callResult = CallExpressionTranslator.translate(expression, null, context).source(expression);
assert callResult instanceof JsExpression;
JsExpression assignment = JsAstUtils.assignment(temporaryVariable.reference(), (JsExpression) callResult);
context.addStatementToCurrentBlock(assignment.makeStmt());
return temporaryVariable.reference(); return temporaryVariable.reference();
} else { } else {
return CallExpressionTranslator.translate(expression, null, context).source(expression); return CallExpressionTranslator.translate(expression, null, context).source(expression);
@@ -16,32 +16,51 @@
package org.jetbrains.k2js.translate.reference; package org.jetbrains.k2js.translate.reference;
import com.google.dart.compiler.backend.js.ast.JsExpression; import com.google.dart.compiler.backend.js.ast.*;
import com.google.dart.compiler.backend.js.ast.JsInvocation;
import com.google.dart.compiler.backend.js.ast.metadata.MetadataPackage; import com.google.dart.compiler.backend.js.ast.metadata.MetadataPackage;
import org.jetbrains.annotations.NotNull; import com.google.dart.compiler.common.SourceInfoImpl;
import org.jetbrains.annotations.Nullable; import com.google.gwt.dev.js.JsParser;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor; import com.google.gwt.dev.js.JsParserException;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.*;
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.JetCallExpression;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage; import org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall; import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall;
import org.jetbrains.jet.lang.types.lang.InlineStrategy; import org.jetbrains.jet.lang.types.lang.InlineStrategy;
import org.jetbrains.jet.lang.types.lang.InlineUtil; import org.jetbrains.jet.lang.types.lang.InlineUtil;
import org.jetbrains.jet.lang.psi.ValueArgument;
import org.jetbrains.k2js.translate.callTranslator.CallTranslator; import org.jetbrains.k2js.translate.callTranslator.CallTranslator;
import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.context.TranslationContext;
import org.jetbrains.k2js.translate.intrinsic.functions.patterns.DescriptorPredicate;
import org.jetbrains.k2js.translate.intrinsic.functions.patterns.PatternBuilder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.k2js.translate.utils.BindingUtils;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import static org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage.getFunctionResolvedCallWithAssert;
public final class CallExpressionTranslator extends AbstractCallExpressionTranslator { public final class CallExpressionTranslator extends AbstractCallExpressionTranslator {
@NotNull @NotNull
public static JsExpression translate( private final static DescriptorPredicate JSCODE_PATTERN = PatternBuilder.pattern("kotlin.js.js(String)");
@NotNull
public static JsNode translate(
@NotNull JetCallExpression expression, @NotNull JetCallExpression expression,
@Nullable JsExpression receiver, @Nullable JsExpression receiver,
@NotNull TranslationContext context @NotNull TranslationContext context
) { ) {
if (matchesJsCode(expression, context)) {
return (new CallExpressionTranslator(expression, receiver, context)).translateJsCode();
}
JsExpression callExpression = (new CallExpressionTranslator(expression, receiver, context)).translate(); JsExpression callExpression = (new CallExpressionTranslator(expression, receiver, context)).translate();
if (shouldBeInlined(expression, context) if (shouldBeInlined(expression, context)
@@ -80,6 +99,16 @@ public final class CallExpressionTranslator extends AbstractCallExpressionTransl
return false; return false;
} }
private static boolean matchesJsCode(
@NotNull JetCallExpression expression,
@NotNull TranslationContext context
) {
FunctionDescriptor descriptor = getFunctionResolvedCallWithAssert(expression, context.bindingContext())
.getResultingDescriptor();
return JSCODE_PATTERN.apply(descriptor) && expression.getValueArguments().size() == 1;
}
private CallExpressionTranslator( private CallExpressionTranslator(
@NotNull JetCallExpression expression, @NotNull JetCallExpression expression,
@Nullable JsExpression receiver, @Nullable JsExpression receiver,
@@ -92,4 +121,47 @@ public final class CallExpressionTranslator extends AbstractCallExpressionTransl
private JsExpression translate() { private JsExpression translate() {
return CallTranslator.INSTANCE$.translate(context(), resolvedCall, receiver); return CallTranslator.INSTANCE$.translate(context(), resolvedCall, receiver);
} }
@NotNull
private JsNode translateJsCode() {
List<? extends ValueArgument> arguments = expression.getValueArguments();
JetExpression argumentExpression = arguments.get(0).getArgumentExpression();
assert argumentExpression != null;
Object jsCode = BindingUtils.getCompileTimeValue(bindingContext(), argumentExpression);
assert jsCode instanceof String: "jsCode must be compile time string";
List<JsStatement> statements = parseJsCode((String) jsCode);
int size = statements.size();
if (size == 0) {
return program().getEmptyStatement();
} else if (size > 1) {
return new JsBlock(statements);
} else {
JsStatement resultStatement = statements.get(0);
if (resultStatement instanceof JsExpressionStatement) {
return ((JsExpressionStatement) resultStatement).getExpression();
}
return resultStatement;
}
}
@NotNull
private List<JsStatement> parseJsCode(@NotNull String jsCode) {
List<JsStatement> statements = new ArrayList<JsStatement>();
try {
SourceInfoImpl info = new SourceInfoImpl(null, 0, 0, 0, 0);
JsScope scope = context().scope();
StringReader reader = new StringReader(jsCode);
statements.addAll(JsParser.parse(info, scope, reader, /* insideFunction= */ true));
} catch (JsParserException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
return statements;
}
} }
@@ -17,6 +17,7 @@
package org.jetbrains.k2js.translate.reference; package org.jetbrains.k2js.translate.reference;
import com.google.dart.compiler.backend.js.ast.JsExpression; import com.google.dart.compiler.backend.js.ast.JsExpression;
import com.google.dart.compiler.backend.js.ast.JsNode;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
@@ -52,15 +53,17 @@ public final class QualifiedExpressionTranslator {
} }
@NotNull @NotNull
public static JsExpression translateQualifiedExpression(@NotNull JetQualifiedExpression expression, public static JsNode translateQualifiedExpression(
@NotNull TranslationContext context) { @NotNull JetQualifiedExpression expression,
@NotNull TranslationContext context
) {
JsExpression receiver = translateReceiver(expression, context); JsExpression receiver = translateReceiver(expression, context);
JetExpression selector = getSelector(expression); JetExpression selector = getSelector(expression);
return dispatchToCorrectTranslator(receiver, selector, context); return dispatchToCorrectTranslator(receiver, selector, context);
} }
@NotNull @NotNull
private static JsExpression dispatchToCorrectTranslator( private static JsNode dispatchToCorrectTranslator(
@Nullable JsExpression receiver, @Nullable JsExpression receiver,
@NotNull JetExpression selector, @NotNull JetExpression selector,
@NotNull TranslationContext context @NotNull TranslationContext context
@@ -73,8 +76,12 @@ public final class QualifiedExpressionTranslator {
if (shouldBeInlined((JetCallExpression) selector, context) && if (shouldBeInlined((JetCallExpression) selector, context) &&
BindingContextUtilPackage.isUsedAsExpression(selector, context.bindingContext())) { BindingContextUtilPackage.isUsedAsExpression(selector, context.bindingContext())) {
TemporaryVariable temporaryVariable = context.declareTemporary(null); TemporaryVariable temporaryVariable = context.declareTemporary(null);
JsExpression result = invokeCallExpressionTranslator(receiver, selector, context);
context.addStatementToCurrentBlock(JsAstUtils.assignment(temporaryVariable.reference(), result).makeStmt()); JsNode result = invokeCallExpressionTranslator(receiver, selector, context);
assert result instanceof JsExpression;
JsExpression assignment = JsAstUtils.assignment(temporaryVariable.reference(), (JsExpression) result);
context.addStatementToCurrentBlock(assignment.makeStmt());
return temporaryVariable.reference(); return temporaryVariable.reference();
} else { } else {
return invokeCallExpressionTranslator(receiver, selector, context); return invokeCallExpressionTranslator(receiver, selector, context);
@@ -88,7 +95,7 @@ public final class QualifiedExpressionTranslator {
} }
@NotNull @NotNull
private static JsExpression invokeCallExpressionTranslator( private static JsNode invokeCallExpressionTranslator(
@Nullable JsExpression receiver, @Nullable JsExpression receiver,
@NotNull JetExpression selector, @NotNull JetExpression selector,
@NotNull TranslationContext context @NotNull TranslationContext context