diff --git a/js/js.translator/js.translator.iml b/js/js.translator/js.translator.iml index 517bbe9302c..6969f8cd869 100644 --- a/js/js.translator/js.translator.iml +++ b/js/js.translator/js.translator.iml @@ -14,5 +14,6 @@ + \ No newline at end of file diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java b/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java index 108ee21c886..50c8845cae5 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/expression/ExpressionVisitor.java @@ -191,8 +191,12 @@ public final class ExpressionVisitor extends TranslatorVisitor { if (shouldBeInlined(expression, context) && BindingContextUtilPackage.isUsedAsExpression(expression, context.bindingContext())) { 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(); } else { return CallExpressionTranslator.translate(expression, null, context).source(expression); diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallExpressionTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallExpressionTranslator.java index 6816b8d8293..faad74a2617 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallExpressionTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/CallExpressionTranslator.java @@ -16,32 +16,51 @@ 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.*; import com.google.dart.compiler.backend.js.ast.metadata.MetadataPackage; -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 com.google.dart.compiler.common.SourceInfoImpl; +import com.google.gwt.dev.js.JsParser; +import com.google.gwt.dev.js.JsParserException; +import org.jetbrains.jet.lang.descriptors.*; 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.model.ResolvedCall; import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall; import org.jetbrains.jet.lang.types.lang.InlineStrategy; 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.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 { @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, @Nullable JsExpression receiver, @NotNull TranslationContext context ) { + if (matchesJsCode(expression, context)) { + return (new CallExpressionTranslator(expression, receiver, context)).translateJsCode(); + } + JsExpression callExpression = (new CallExpressionTranslator(expression, receiver, context)).translate(); if (shouldBeInlined(expression, context) @@ -80,6 +99,16 @@ public final class CallExpressionTranslator extends AbstractCallExpressionTransl 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( @NotNull JetCallExpression expression, @Nullable JsExpression receiver, @@ -92,4 +121,47 @@ public final class CallExpressionTranslator extends AbstractCallExpressionTransl private JsExpression translate() { return CallTranslator.INSTANCE$.translate(context(), resolvedCall, receiver); } + + @NotNull + private JsNode translateJsCode() { + List 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 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 parseJsCode(@NotNull String jsCode) { + List statements = new ArrayList(); + + 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; + } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/reference/QualifiedExpressionTranslator.java b/js/js.translator/src/org/jetbrains/k2js/translate/reference/QualifiedExpressionTranslator.java index 0a0af77c9ce..dc4042d2d1b 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/reference/QualifiedExpressionTranslator.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/reference/QualifiedExpressionTranslator.java @@ -17,6 +17,7 @@ package org.jetbrains.k2js.translate.reference; 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.Nullable; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; @@ -52,15 +53,17 @@ public final class QualifiedExpressionTranslator { } @NotNull - public static JsExpression translateQualifiedExpression(@NotNull JetQualifiedExpression expression, - @NotNull TranslationContext context) { + public static JsNode translateQualifiedExpression( + @NotNull JetQualifiedExpression expression, + @NotNull TranslationContext context + ) { JsExpression receiver = translateReceiver(expression, context); JetExpression selector = getSelector(expression); return dispatchToCorrectTranslator(receiver, selector, context); } @NotNull - private static JsExpression dispatchToCorrectTranslator( + private static JsNode dispatchToCorrectTranslator( @Nullable JsExpression receiver, @NotNull JetExpression selector, @NotNull TranslationContext context @@ -73,8 +76,12 @@ public final class QualifiedExpressionTranslator { if (shouldBeInlined((JetCallExpression) selector, context) && BindingContextUtilPackage.isUsedAsExpression(selector, context.bindingContext())) { 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(); } else { return invokeCallExpressionTranslator(receiver, selector, context); @@ -88,7 +95,7 @@ public final class QualifiedExpressionTranslator { } @NotNull - private static JsExpression invokeCallExpressionTranslator( + private static JsNode invokeCallExpressionTranslator( @Nullable JsExpression receiver, @NotNull JetExpression selector, @NotNull TranslationContext context