From a7a695f203b58477c5b775e53e59825d1204af2d Mon Sep 17 00:00:00 2001 From: Svyatoslav Kuzmich Date: Thu, 7 Jun 2018 16:29:37 +0300 Subject: [PATCH] KJS: Add JsLoop AST interface and corresponding visitors --- .../kotlin/js/backend/ast/JsFor.java | 2 +- .../kotlin/js/backend/ast/JsForIn.java | 2 +- .../kotlin/js/backend/ast/JsLoop.java | 14 ++++++ .../kotlin/js/backend/ast/JsVisitor.kt | 11 +++-- .../js/backend/ast/JsVisitorWithContext.java | 19 ++++++-- .../kotlin/js/backend/ast/JsWhile.java | 2 +- .../inline/clean/DoWhileGuardElimination.kt | 12 +----- .../LabeledBlockToDoWhileTransformation.kt | 31 +++---------- .../clean/TemporaryVariableElimination.kt | 8 +--- .../rewriters/ContinueReplacingVisitor.kt | 43 +------------------ 10 files changed, 49 insertions(+), 95 deletions(-) create mode 100644 js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsLoop.java diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsFor.java b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsFor.java index d2d97f21ad4..98054847f77 100644 --- a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsFor.java +++ b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsFor.java @@ -18,7 +18,7 @@ import org.jetbrains.annotations.NotNull; * Note that any of the parts of the for loop header can be * null, although the body will never be null. */ -public class JsFor extends SourceInfoAwareJsNode implements JsStatement { +public class JsFor extends SourceInfoAwareJsNode implements JsLoop { private JsStatement body; private JsExpression condition; private JsExpression incrementExpression; diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsForIn.java b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsForIn.java index 5be526bacc4..2ccf7c896fa 100644 --- a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsForIn.java +++ b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsForIn.java @@ -7,7 +7,7 @@ package org.jetbrains.kotlin.js.backend.ast; import org.jetbrains.kotlin.js.util.AstUtil; import org.jetbrains.annotations.NotNull; -public class JsForIn extends SourceInfoAwareJsNode implements JsStatement { +public class JsForIn extends SourceInfoAwareJsNode implements JsLoop { private JsStatement body; private JsExpression iterExpression; private JsExpression objectExpression; diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsLoop.java b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsLoop.java new file mode 100644 index 00000000000..4eb63b51712 --- /dev/null +++ b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsLoop.java @@ -0,0 +1,14 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.js.backend.ast; + +import org.jetbrains.annotations.NotNull; + +public interface JsLoop extends JsStatement { + @NotNull + @Override + JsStatement deepCopy(); +} diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsVisitor.kt b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsVisitor.kt index e06e060057f..e9dadd6c5c6 100644 --- a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsVisitor.kt +++ b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsVisitor.kt @@ -64,7 +64,7 @@ abstract class JsVisitor { visitElement(x) open fun visitDoWhile(x: JsDoWhile): Unit = - visitElement(x) + visitLoop(x) open fun visitEmpty(x: JsEmpty): Unit = visitElement(x) @@ -73,10 +73,10 @@ abstract class JsVisitor { visitElement(x) open fun visitFor(x: JsFor): Unit = - visitElement(x) + visitLoop(x) open fun visitForIn(x: JsForIn): Unit = - visitElement(x) + visitLoop(x) open fun visitFunction(x: JsFunction): Unit = visitElement(x) @@ -90,6 +90,9 @@ abstract class JsVisitor { open fun visitLabel(x: JsLabel): Unit = visitElement(x) + open fun visitLoop(x: JsLoop): Unit = + visitElement(x) + open fun visitNameRef(nameRef: JsNameRef): Unit = visitElement(nameRef) @@ -151,7 +154,7 @@ abstract class JsVisitor { visitElement(x) open fun visitWhile(x: JsWhile): Unit = - visitElement(x) + visitLoop(x) open fun visitDocComment(comment: JsDocComment): Unit = visitElement(comment) diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsVisitorWithContext.java b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsVisitorWithContext.java index 95c5dc6945d..9dd219f35c6 100644 --- a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsVisitorWithContext.java +++ b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsVisitorWithContext.java @@ -104,6 +104,7 @@ public abstract class JsVisitorWithContext { } public void endVisit(@NotNull JsDoWhile x, @NotNull JsContext ctx) { + endVisit((JsLoop) x, ctx); } public void endVisit(@NotNull JsEmpty x, @NotNull JsContext ctx) { @@ -113,9 +114,11 @@ public abstract class JsVisitorWithContext { } public void endVisit(@NotNull JsFor x, @NotNull JsContext ctx) { + endVisit((JsLoop) x, ctx); } public void endVisit(@NotNull JsForIn x, @NotNull JsContext ctx) { + endVisit((JsLoop) x, ctx); } public void endVisit(@NotNull JsFunction x, @NotNull JsContext ctx) { @@ -132,6 +135,9 @@ public abstract class JsVisitorWithContext { public void endVisit(@NotNull JsLabel x, @NotNull JsContext ctx) { } + public void endVisit(@NotNull JsLoop x, @NotNull JsContext ctx) { + } + public void endVisit(@NotNull JsName x, @NotNull JsContext ctx) { } @@ -202,6 +208,7 @@ public abstract class JsVisitorWithContext { } public void endVisit(@NotNull JsWhile x, @NotNull JsContext ctx) { + endVisit((JsLoop) x, ctx); } public boolean visit(@NotNull JsArrayAccess x, @NotNull JsContext ctx) { @@ -253,7 +260,7 @@ public abstract class JsVisitorWithContext { } public boolean visit(@NotNull JsDoWhile x, @NotNull JsContext ctx) { - return true; + return visit((JsLoop) x, ctx); } public boolean visit(@NotNull JsEmpty x, @NotNull JsContext ctx) { @@ -265,11 +272,11 @@ public abstract class JsVisitorWithContext { } public boolean visit(@NotNull JsFor x, @NotNull JsContext ctx) { - return true; + return visit((JsLoop) x, ctx); } public boolean visit(@NotNull JsForIn x, @NotNull JsContext ctx) { - return true; + return visit((JsLoop) x, ctx); } public boolean visit(@NotNull JsFunction x, @NotNull JsContext ctx) { @@ -288,6 +295,10 @@ public abstract class JsVisitorWithContext { return true; } + public boolean visit(@NotNull JsLoop x, @NotNull JsContext ctx) { + return true; + } + public boolean visit(@NotNull JsName x, @NotNull JsContext ctx) { return true; } @@ -369,7 +380,7 @@ public abstract class JsVisitorWithContext { } public boolean visit(@NotNull JsWhile x, @NotNull JsContext ctx) { - return true; + return visit((JsLoop) x, ctx); } protected abstract T doAccept(T node); diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsWhile.java b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsWhile.java index 91983b0815d..1c7c312f299 100644 --- a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsWhile.java +++ b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsWhile.java @@ -10,7 +10,7 @@ import org.jetbrains.annotations.NotNull; /** * A JavaScript while statement. */ -public class JsWhile extends SourceInfoAwareJsNode implements JsStatement { +public class JsWhile extends SourceInfoAwareJsNode implements JsLoop { protected JsStatement body; protected JsExpression condition; diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/DoWhileGuardElimination.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/DoWhileGuardElimination.kt index 4e837e41c57..bea916cfbbe 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/DoWhileGuardElimination.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/DoWhileGuardElimination.kt @@ -123,17 +123,9 @@ internal class DoWhileGuardElimination(private val root: JsStatement) { private fun isInLoop() = loopLevel > 0 - override fun visitDoWhile(x: JsDoWhile) = enterLoop { super.visitDoWhile(x) } - - override fun visitWhile(x: JsWhile) = enterLoop { super.visitWhile(x) } - - override fun visitFor(x: JsFor) = enterLoop { super.visitFor(x) } - - override fun visitForIn(x: JsForIn) = enterLoop { super.visitForIn(x) } - - private inline fun enterLoop(action: () -> Unit) { + override fun visitLoop(x: JsLoop) { loopLevel++ - action() + super.visitLoop(x) loopLevel-- } diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/LabeledBlockToDoWhileTransformation.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/LabeledBlockToDoWhileTransformation.kt index 53898bbc7ae..cd91f0db600 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/LabeledBlockToDoWhileTransformation.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/LabeledBlockToDoWhileTransformation.kt @@ -28,14 +28,6 @@ object LabeledBlockToDoWhileTransformation { } } - fun JsStatement.isLoop(): Boolean = when (this) { - is JsWhile, - is JsDoWhile, - is JsFor, - is JsForIn -> true - else -> false - } - fun apply(root: JsNode) { object : JsVisitorWithContextImpl() { val loopStack = Stack() @@ -58,28 +50,18 @@ object LabeledBlockToDoWhileTransformation { } override fun visit(x: JsLabel, ctx: JsContext): Boolean { - if (x.statement.isLoop()) { + if (x.statement is JsLoop) { loopLabels[x.statement] = x } return true } - override fun visit(x: JsWhile, ctx: JsContext) = visitLoop(x) - override fun visit(x: JsDoWhile, ctx: JsContext) = visitLoop(x) - override fun visit(x: JsFor, ctx: JsContext) = visitLoop(x) - override fun visit(x: JsForIn, ctx: JsContext) = visitLoop(x) - - override fun endVisit(x: JsWhile, ctx: JsContext) = endVisitLoop(x, ctx) - override fun endVisit(x: JsDoWhile, ctx: JsContext) = endVisitLoop(x, ctx) - override fun endVisit(x: JsFor, ctx: JsContext) = endVisitLoop(x, ctx) - override fun endVisit(x: JsForIn, ctx: JsContext) = endVisitLoop(x, ctx) - - private fun visitLoop(x: JsStatement): Boolean { + override fun visit(x: JsLoop, ctx: JsContext): Boolean { loopStack.push(x) return true } - private fun endVisitLoop(x: JsStatement, ctx: JsContext) { + override fun endVisit(x: JsLoop, ctx: JsContext) { loopStack.pop() if (loopsToLabel.contains(x)) { // Reuse loop label if present. Otherwise create new label. @@ -102,11 +84,8 @@ object LabeledBlockToDoWhileTransformation { */ private fun labelLoopBreaksAndContinues(loop: JsStatement, fakeLoops: Set, label: JsNameRef) { object : JsVisitorWithContextImpl() { - override fun visit(x: JsWhile, ctx: JsContext): Boolean = visitLoop(x) - override fun visit(x: JsDoWhile, ctx: JsContext): Boolean = visitLoop(x) - override fun visit(x: JsFor, ctx: JsContext): Boolean = visitLoop(x) - override fun visit(x: JsForIn, ctx: JsContext): Boolean = visitLoop(x) - private fun visitLoop(x: JsStatement): Boolean = fakeLoops.contains(x) || x === loop + override fun visit(x: JsLoop, ctx: JsContext): Boolean = + fakeLoops.contains(x) || x === loop override fun endVisit(x: JsBreak, ctx: JsContext) { if (x.label == null) diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/TemporaryVariableElimination.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/TemporaryVariableElimination.kt index 1ae9ae37e8c..4a393eaca9a 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/TemporaryVariableElimination.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/TemporaryVariableElimination.kt @@ -183,13 +183,7 @@ internal class TemporaryVariableElimination(private val function: JsFunction) { } } - override fun visitFor(x: JsFor) = withNewScope { super.visitFor(x) } - - override fun visitForIn(x: JsForIn) = withNewScope { super.visitForIn(x) } - - override fun visitWhile(x: JsWhile) = withNewScope { super.visitWhile(x) } - - override fun visitDoWhile(x: JsDoWhile) = withNewScope { super.visitDoWhile(x) } + override fun visitLoop(x: JsLoop) = withNewScope { super.visitLoop(x) } override fun visitIf(x: JsIf) { accept(x.ifExpression) diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/util/rewriters/ContinueReplacingVisitor.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/util/rewriters/ContinueReplacingVisitor.kt index 5b136165bdc..6a53bef49b8 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/util/rewriters/ContinueReplacingVisitor.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/util/rewriters/ContinueReplacingVisitor.kt @@ -34,53 +34,14 @@ class ContinueReplacingVisitor(val loopLabelName: JsName?, val guardLabelName: J return false } - override fun visit(x: JsWhile, ctx: JsContext): Boolean { + override fun visit(x: JsLoop, ctx: JsContext): Boolean { if (loopLabelName == null) return false loopNestingLevel++ return super.visit(x, ctx) } - override fun endVisit(x: JsWhile, ctx: JsContext) { - super.endVisit(x, ctx) - if (loopLabelName == null) return - loopNestingLevel-- - } - - override fun visit(x: JsDoWhile, ctx: JsContext): Boolean { - if (loopLabelName == null) return false - - loopNestingLevel++ - return super.visit(x, ctx) - } - - override fun endVisit(x: JsDoWhile, ctx: JsContext) { - super.endVisit(x, ctx) - if (loopLabelName == null) return - loopNestingLevel-- - } - - override fun visit(x: JsFor, ctx: JsContext): Boolean { - if (loopLabelName == null) return false - - loopNestingLevel++ - return super.visit(x, ctx) - } - - override fun endVisit(x: JsFor, ctx: JsContext) { - super.endVisit(x, ctx) - if (loopLabelName == null) return - loopNestingLevel-- - } - - override fun visit(x: JsForIn, ctx: JsContext): Boolean { - if (loopLabelName == null) return false - - loopNestingLevel++ - return super.visit(x, ctx) - } - - override fun endVisit(x: JsForIn, ctx: JsContext) { + override fun endVisit(x: JsLoop, ctx: JsContext) { super.endVisit(x, ctx) if (loopLabelName == null) return loopNestingLevel--