JS: refactor Dart AST

This commit is contained in:
Alexey Andreev
2016-10-19 18:36:20 +03:00
parent bec1e526a1
commit fd158a6922
19 changed files with 64 additions and 147 deletions
@@ -9,6 +9,6 @@ import java.util.List;
/**
* Implemented by JavaScript objects that accept arguments.
*/
public interface HasArguments extends JsExpression {
public interface HasArguments {
List<JsExpression> getArguments();
}
@@ -10,7 +10,7 @@ import org.jetbrains.annotations.NotNull;
/**
* Represents a javascript expression for array access.
*/
public final class JsArrayAccess extends JsExpressionImpl {
public final class JsArrayAccess extends JsExpression {
private JsExpression arrayExpression;
private JsExpression indexExpression;
@@ -8,7 +8,7 @@ import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public final class JsBinaryOperation extends JsExpressionImpl {
public final class JsBinaryOperation extends JsExpression {
private JsExpression arg1;
private JsExpression arg2;
@@ -7,7 +7,7 @@ package com.google.dart.compiler.backend.js.ast;
import com.google.dart.compiler.util.AstUtil;
import org.jetbrains.annotations.NotNull;
public final class JsConditional extends JsExpressionImpl {
public final class JsConditional extends JsExpression {
private JsExpression testExpression;
private JsExpression elseExpression;
private JsExpression thenExpression;
@@ -5,7 +5,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.Map;
public class JsDocComment extends JsExpressionImpl {
public class JsDocComment extends JsExpression {
private final Map<String, Object> tags;
public JsDocComment(Map<String, Object> tags) {
@@ -1,47 +0,0 @@
/*
* Copyright 2010-2014 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 com.google.dart.compiler.backend.js.ast;
import org.jetbrains.annotations.NotNull;
public class JsEmptyExpression extends JsExpressionImpl {
JsEmptyExpression() {
}
@Override
@NotNull
public JsStatement makeStmt() {
return JsEmpty.INSTANCE;
}
@Override
public void accept(JsVisitor visitor) {
throw new IllegalArgumentException("empty expression should not be here during generating Javascript code");
}
@Override
public void traverse(JsVisitorWithContext visitor, JsContext ctx) {
throw new IllegalArgumentException("empty expression should not be here during generating Javascript code");
}
@NotNull
@Override
public JsEmptyExpression deepCopy() {
return new JsEmptyExpression();
}
}
@@ -1,17 +1,50 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import org.jetbrains.annotations.NotNull;
public interface JsExpression extends JsNode {
boolean isLeaf();
import java.util.List;
public abstract class JsExpression extends SourceInfoAwareJsNode {
/**
* Determines whether or not this expression is a leaf, such as a
* {@link JsNameRef}, {@link JsLiteral.JsBooleanLiteral}, and so on. Leaf expressions
* never need to be parenthesized.
*/
public boolean isLeaf() {
// Conservatively say that it isn't a leaf.
// Individual subclasses can speak for themselves if they are a leaf.
return false;
}
@NotNull
JsStatement makeStmt();
public JsStatement makeStmt() {
return new JsExpressionStatement(this);
}
protected abstract static class JsExpressionHasArguments extends JsExpression implements HasArguments {
protected final List<JsExpression> arguments;
public JsExpressionHasArguments(List<JsExpression> arguments) {
this.arguments = arguments;
}
@Override
public List<JsExpression> getArguments() {
return arguments;
}
}
@Override
JsExpression source(Object info);
public JsExpression source(Object info) {
setSource(info);
return this;
}
@NotNull
@Override
JsExpression deepCopy();
public abstract JsExpression deepCopy();
}
@@ -1,48 +0,0 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.backend.js.ast;
import org.jetbrains.annotations.NotNull;
import java.util.List;
abstract class JsExpressionImpl extends SourceInfoAwareJsNode implements JsExpression {
/**
* Determines whether or not this expression is a leaf, such as a
* {@link JsNameRef}, {@link JsLiteral.JsBooleanLiteral}, and so on. Leaf expressions
* never need to be parenthesized.
*/
@Override
public boolean isLeaf() {
// Conservatively say that it isn't a leaf.
// Individual subclasses can speak for themselves if they are a leaf.
return false;
}
@Override
@NotNull
public JsStatement makeStmt() {
return new JsExpressionStatement(this);
}
protected abstract static class JsExpressionHasArguments extends JsExpressionImpl implements HasArguments {
protected final List<JsExpression> arguments;
public JsExpressionHasArguments(List<JsExpression> arguments) {
this.arguments = arguments;
}
@Override
public List<JsExpression> getArguments() {
return arguments;
}
}
@Override
public JsExpression source(Object info) {
setSource(info);
return this;
}
}
@@ -10,7 +10,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.List;
public final class JsInvocation extends JsExpressionImpl.JsExpressionHasArguments {
public final class JsInvocation extends JsExpression.JsExpressionHasArguments {
@NotNull
private JsExpression qualifier;
@@ -6,7 +6,7 @@ package com.google.dart.compiler.backend.js.ast;
import org.jetbrains.annotations.NotNull;
public abstract class JsLiteral extends JsExpressionImpl {
public abstract class JsLiteral extends JsExpression {
public static final JsValueLiteral THIS = new JsThisRef();
public static final JsNameRef UNDEFINED = new JsNameRef("undefined");
@@ -12,7 +12,7 @@ import org.jetbrains.annotations.Nullable;
/**
* Represents a JavaScript expression that references a name.
*/
public final class JsNameRef extends JsExpressionImpl implements HasName {
public final class JsNameRef extends JsExpression implements HasName {
private String ident;
private JsName name;
private JsExpression qualifier;
@@ -10,7 +10,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.List;
public final class JsNew extends JsExpressionImpl.JsExpressionHasArguments {
public final class JsNew extends JsExpression.JsExpressionHasArguments {
private JsExpression constructorExpression;
public JsNew(JsExpression constructorExpression) {
@@ -4,7 +4,7 @@
package com.google.dart.compiler.backend.js.ast;
public abstract class JsUnaryOperation extends JsExpressionImpl {
public abstract class JsUnaryOperation extends JsExpression {
private JsExpression arg;
@@ -21,7 +21,6 @@ import com.google.dart.compiler.backend.js.ast.metadata.*
import com.intellij.util.SmartList
import org.jetbrains.kotlin.js.inline.util.IdentitySet
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
import org.jetbrains.kotlin.js.inline.util.canHaveOwnSideEffect
import org.jetbrains.kotlin.js.inline.util.rewriters.ContinueReplacingVisitor
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.*
import org.jetbrains.kotlin.js.translate.utils.jsAstUtils.*
@@ -296,14 +295,14 @@ internal class ExpressionDecomposer private constructor(
// Qualifier might be a reference to lambda property. See KT-7674
// An exception here is `fn.call()`, which are marked as side effect free. Further recognition of such
// case in inliner might be quite difficult, so never extract such call (and other calls marked this way).
if ((qualifier as? HasMetadata)?.sideEffects == SideEffectKind.PURE &&
callee != null && receiver != null && receiver in containsNodeWithSideEffect
if (qualifier.sideEffects == SideEffectKind.PURE && callee != null && receiver != null &&
receiver in containsNodeWithSideEffect
) {
val receiverTmp = receiver.extractToTemporary()
callee.qualifier = receiverTmp
}
else {
if (receiver != null && callee != null && applyBindIfNecessary) {
if (receiver != null && applyBindIfNecessary) {
val receiverTmp = receiver.extractToTemporary()
qualifier = JsAstUtils.invokeBind(receiverTmp, pureFqn(callee.ident, receiverTmp))
}
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.js.inline.util
import com.google.dart.compiler.backend.js.ast.*
import com.google.dart.compiler.backend.js.ast.metadata.HasMetadata
import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind
import com.google.dart.compiler.backend.js.ast.metadata.sideEffects
import org.jetbrains.kotlin.js.translate.utils.jsAstUtils.any
@@ -30,6 +29,5 @@ fun JsExpression.canHaveOwnSideEffect(vars: Set<JsName>) = when (this) {
is JsLiteral -> false
is JsBinaryOperation -> operator.isAssignment
is JsNameRef -> name !in vars && sideEffects != SideEffectKind.PURE
is HasMetadata -> sideEffects != SideEffectKind.PURE
else -> true
else -> sideEffects != SideEffectKind.PURE
}
@@ -18,10 +18,12 @@ package org.jetbrains.kotlin.js.translate.callTranslator
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.metadata.HasMetadata
import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind
import com.google.dart.compiler.backend.js.ast.metadata.sideEffects
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator
@@ -84,7 +86,7 @@ fun VariableAccessInfo.constructAccessExpression(ref: JsExpression): JsExpressio
// This is useful when passing AST to TemporaryAssignmentElimination. It can bring
// property assignment like `obj.propertyName = $tmp` to places where `$tmp` gets its value,
// but only when it's sure that no side effects possible.
(ref as? HasMetadata)?.let { it.sideEffects = SideEffectKind.PURE }
ref.sideEffects = SideEffectKind.PURE
JsAstUtils.assignment(ref, value!!)
}
}
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.js.translate.context;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.dart.compiler.backend.js.ast.*;
import com.google.dart.compiler.backend.js.ast.metadata.HasMetadata;
import com.google.dart.compiler.backend.js.ast.metadata.MetadataProperties;
import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind;
import com.intellij.openapi.util.Factory;
@@ -619,13 +618,11 @@ public final class StaticContext {
}
private static JsExpression applySideEffects(JsExpression expression, DeclarationDescriptor descriptor) {
if (expression instanceof HasMetadata) {
if (descriptor instanceof FunctionDescriptor ||
descriptor instanceof PackageFragmentDescriptor ||
descriptor instanceof ClassDescriptor
) {
MetadataProperties.setSideEffects((HasMetadata) expression, SideEffectKind.PURE);
}
if (descriptor instanceof FunctionDescriptor ||
descriptor instanceof PackageFragmentDescriptor ||
descriptor instanceof ClassDescriptor
) {
MetadataProperties.setSideEffects(expression, SideEffectKind.PURE);
}
return expression;
}
@@ -20,7 +20,6 @@ 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.backend.js.ast.metadata.HasMetadata;
import com.google.dart.compiler.backend.js.ast.metadata.MetadataProperties;
import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind;
import org.jetbrains.annotations.NotNull;
@@ -28,13 +28,12 @@ import org.jetbrains.kotlin.js.translate.context.TranslationContext;
import org.jetbrains.kotlin.types.expressions.OperatorConventions;
import org.jetbrains.kotlin.util.OperatorNameConventions;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public final class JsAstUtils {
private static final JsNameRef DEFINE_PROPERTY = pureFqn("defineProperty", null);
public static final JsNameRef CREATE_OBJECT = pureFqn("create", null);
private static final JsNameRef CREATE_OBJECT = pureFqn("create", null);
private static final JsNameRef VALUE = new JsNameRef("value");
private static final JsPropertyInitializer WRITABLE = new JsPropertyInitializer(pureFqn("writable", null), JsLiteral.TRUE);
@@ -205,11 +204,6 @@ public final class JsAstUtils {
return invokeMethod(Namer.kotlinLong(), Namer.LONG_FROM_NUMBER, expression);
}
@NotNull
public static JsExpression equalsForObject(@NotNull JsExpression left, @NotNull JsExpression right) {
return invokeMethod(left, Namer.EQUALS_METHOD_NAME, right);
}
@NotNull
public static JsExpression compareForObject(@NotNull JsExpression left, @NotNull JsExpression right) {
return invokeMethod(left, Namer.COMPARE_TO_METHOD_NAME, right);
@@ -267,7 +261,7 @@ public final class JsAstUtils {
return new JsBinaryOperation(JsBinaryOperator.OR, op1, op2);
}
public static void setQualifier(@NotNull JsExpression selector, @Nullable JsExpression receiver) {
private static void setQualifier(@NotNull JsExpression selector, @Nullable JsExpression receiver) {
assert (selector instanceof JsInvocation || selector instanceof JsNameRef);
if (selector instanceof JsInvocation) {
setQualifier(((JsInvocation) selector).getQualifier(), receiver);
@@ -398,16 +392,6 @@ public final class JsAstUtils {
return new JsVars(new JsVars.JsVar(name, expr));
}
public static void setArguments(@NotNull HasArguments invocation, @NotNull List<JsExpression> newArgs) {
List<JsExpression> arguments = invocation.getArguments();
assert arguments.isEmpty() : "Arguments already set.";
arguments.addAll(newArgs);
}
public static void setArguments(@NotNull HasArguments invocation, JsExpression... arguments) {
setArguments(invocation, Arrays.asList(arguments));
}
public static void setParameters(@NotNull JsFunction function, @NotNull List<JsParameter> newParams) {
List<JsParameter> parameters = function.getParameters();
assert parameters.isEmpty() : "Arguments already set.";