JS backend: added visitors with context

This commit is contained in:
Alexey Tsvetkov
2014-08-14 15:29:03 +04:00
committed by Zalim Bashorov
parent 15e963de25
commit 915f8734c5
48 changed files with 1002 additions and 14 deletions
@@ -51,4 +51,9 @@ public class ChameleonJsExpression implements JsExpression {
public JsExpression source(Object info) {
return expression.source(info);
}
@Override
public void traverse(JsVisitorWithContext visitor, JsContext ctx) {
expression.traverse(visitor, ctx);
}
}
@@ -46,4 +46,13 @@ public final class JsArrayAccess extends JsExpressionImpl {
visitor.accept(arrayExpression);
visitor.accept(indexExpression);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
arrayExpression = v.accept(arrayExpression);
indexExpression = v.accept(indexExpression);
}
v.endVisit(this, ctx);
}
}
@@ -35,4 +35,12 @@ public final class JsArrayLiteral extends JsLiteral {
public void acceptChildren(JsVisitor visitor) {
visitor.acceptWithInsertRemove(expressions);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
v.acceptList(expressions);
}
v.endVisit(this, ctx);
}
}
@@ -48,4 +48,17 @@ public final class JsBinaryOperation extends JsExpressionImpl {
}
visitor.accept(arg2);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
if (op.isAssignment()) {
arg1 = v.acceptLvalue(arg1);
} else {
arg1 = v.accept(arg1);
}
arg2 = v.accept(arg2);
}
v.endVisit(this, ctx);
}
}
@@ -7,8 +7,6 @@ package com.google.dart.compiler.backend.js.ast;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
@@ -56,4 +54,12 @@ public class JsBlock extends SourceInfoAwareJsNode implements JsStatement {
public void acceptChildren(JsVisitor visitor) {
visitor.acceptWithInsertRemove(statements);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
v.acceptStatementList(statements);
}
v.endVisit(this, ctx);
}
}
@@ -20,4 +20,10 @@ public final class JsBreak extends JsContinue {
public void accept(JsVisitor v) {
v.visitBreak(this);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
v.visit(this, ctx);
v.endVisit(this, ctx);
}
}
@@ -32,4 +32,13 @@ public final class JsCase extends JsSwitchMember {
visitor.accept(caseExpression);
super.acceptChildren(visitor);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
caseExpression = v.accept(caseExpression);
v.acceptStatementList(statements);
}
v.endVisit(this, ctx);
}
}
@@ -60,4 +60,16 @@ public class JsCatch extends SourceInfoAwareJsNode implements HasCondition {
}
visitor.accept(body);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
param = v.accept(param);
if (condition != null) {
condition = v.accept(condition);
}
body = v.accept(body);
}
v.endVisit(this, ctx);
}
}
@@ -53,4 +53,14 @@ public final class JsConditional extends JsExpressionImpl {
visitor.accept(thenExpression);
visitor.accept(elseExpression);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
testExpression = v.accept(testExpression);
thenExpression = v.accept(thenExpression);
elseExpression = v.accept(elseExpression);
}
v.endVisit(this, ctx);
}
}
@@ -4,6 +4,8 @@
package com.google.dart.compiler.backend.js.ast;
import org.jetbrains.annotations.Nullable;
/**
* The context in which a JsNode visitation occurs. This represents the set of
* possible operations a JsVisitor subclass can perform on the currently visited
@@ -23,4 +25,7 @@ public interface JsContext {
void removeMe();
void replaceMe(JsNode node);
@Nullable
JsNode getCurrentNode();
}
@@ -26,4 +26,10 @@ public class JsContinue extends SourceInfoAwareJsNode implements JsStatement {
public void accept(JsVisitor v) {
v.visitContinue(this);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
v.visit(this, ctx);
v.endVisit(this, ctx);
}
}
@@ -20,4 +20,10 @@ public class JsDebugger extends SourceInfoAwareJsNode implements JsStatement {
public void acceptChildren(JsVisitor visitor) {
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
v.visit(this, ctx);
v.endVisit(this, ctx);
}
}
@@ -12,4 +12,12 @@ public final class JsDefault extends JsSwitchMember {
public void accept(JsVisitor v) {
v.visitDefault(this);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
v.acceptStatementList(statements);
}
v.endVisit(this, ctx);
}
}
@@ -19,4 +19,13 @@ public class JsDoWhile extends JsWhile {
public void accept(JsVisitor v) {
v.visitDoWhile(this);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
body = v.acceptStatement(body);
condition = v.accept(condition);
}
v.endVisit(this, ctx);
}
}
@@ -26,4 +26,8 @@ public class JsDocComment extends JsExpressionImpl {
public void accept(JsVisitor v) {
v.visitDocComment(this);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
}
}
@@ -12,4 +12,10 @@ public class JsEmpty extends SourceInfoAwareJsNode implements JsStatement {
public void accept(JsVisitor v) {
v.visitEmpty(this);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
v.visit(this, ctx);
v.endVisit(this, ctx);
}
}
@@ -33,4 +33,9 @@ public class JsEmptyExpression extends JsExpressionImpl {
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");
}
}
@@ -39,4 +39,12 @@ public final class JsExpressionStatement extends AbstractNode implements JsState
public JsNode source(Object info) {
throw new IllegalStateException("You must not set source info for JsExpressionStatement, set for expression");
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
expression = v.accept(expression);
}
v.endVisit(this, ctx);
}
}
@@ -95,4 +95,27 @@ public class JsFor extends SourceInfoAwareJsNode implements JsStatement {
}
visitor.accept(body);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
assert (!(initExpression != null && initVars != null));
if (initExpression != null) {
initExpression = v.accept(initExpression);
} else if (initVars != null) {
initVars = v.accept(initVars);
}
if (condition != null) {
condition = v.accept(condition);
}
if (incrementExpression != null) {
incrementExpression = v.accept(incrementExpression);
}
body = v.acceptStatement(body);
}
v.endVisit(this, ctx);
}
}
@@ -61,4 +61,16 @@ public class JsForIn extends SourceInfoAwareJsNode implements JsStatement {
visitor.accept(objectExpression);
visitor.accept(body);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
if (iterExpression != null) {
iterExpression = v.acceptLvalue(iterExpression);
}
objectExpression = v.accept(objectExpression);
body = v.acceptStatement(body);
}
v.endVisit(this, ctx);
}
}
@@ -76,7 +76,16 @@ public final class JsFunction extends JsLiteral implements HasName {
@Override
public void acceptChildren(JsVisitor visitor) {
visitor.acceptWithInsertRemove(params);
visitor.acceptWithInsertRemove(getParameters());
visitor.accept(body);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
v.acceptList(getParameters());
body = v.accept(body);
}
v.endVisit(this, ctx);
}
}
@@ -63,4 +63,16 @@ public final class JsIf extends SourceInfoAwareJsNode implements JsStatement {
visitor.accept(elseStatement);
}
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
ifExpression = v.accept(ifExpression);
thenStatement = v.acceptStatement(thenStatement);
if (elseStatement != null) {
elseStatement = v.acceptStatement(elseStatement);
}
}
v.endVisit(this, ctx);
}
}
@@ -8,7 +8,6 @@ import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public final class JsInvocation extends JsExpressionImpl.JsExpressionHasArguments {
@@ -60,4 +59,13 @@ public final class JsInvocation extends JsExpressionImpl.JsExpressionHasArgument
visitor.accept(qualifier);
visitor.acceptList(arguments);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
qualifier = v.accept(qualifier);
v.acceptList(arguments);
}
v.endVisit(this, ctx);
}
}
@@ -50,4 +50,12 @@ public class JsLabel extends SourceInfoAwareJsNode implements JsStatement, HasNa
public void acceptChildren(JsVisitor visitor) {
visitor.accept(statement);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
statement = v.acceptStatement(statement);
}
v.endVisit(this, ctx);
}
}
@@ -26,24 +26,36 @@ public abstract class JsLiteral extends JsExpressionImpl {
public void accept(JsVisitor v) {
v.visitThis(this);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
v.visit(this, ctx);
v.endVisit(this, ctx);
}
}
public static final class JsBooleanLiteral extends JsValueLiteral {
private final boolean value;
private final boolean value;
// Should be interned by JsProgram
private JsBooleanLiteral(boolean value) {
// Should be interned by JsProgram
private JsBooleanLiteral(boolean value) {
this.value = value;
}
public boolean getValue() {
public boolean getValue() {
return value;
}
@Override
public void accept(JsVisitor v) {
@Override
public void accept(JsVisitor v) {
v.visitBoolean(this);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
v.visit(this, ctx);
v.endVisit(this, ctx);
}
}
/**
@@ -79,4 +79,14 @@ public final class JsNameRef extends JsExpressionImpl implements HasName {
visitor.accept(qualifier);
}
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
if (qualifier != null) {
qualifier = v.accept(qualifier);
}
}
v.endVisit(this, ctx);
}
}
@@ -34,4 +34,13 @@ public final class JsNew extends JsExpressionImpl.JsExpressionHasArguments {
visitor.accept(constructorExpression);
visitor.acceptList(arguments);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
constructorExpression = v.accept(constructorExpression);
v.acceptList(arguments);
}
v.endVisit(this, ctx);
}
}
@@ -27,4 +27,12 @@ public interface JsNode {
void setSource(Object info);
JsNode source(Object info);
/**
* Causes this object to have the visitor visit itself and its children.
*
* @param visitor the visitor that should traverse this node
* @param ctx the context of an existing traversal
*/
void traverse(JsVisitorWithContext visitor, JsContext ctx);
}
@@ -12,4 +12,10 @@ public final class JsNullLiteral extends JsLiteral.JsValueLiteral {
public void accept(JsVisitor v) {
v.visitNull(this);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
v.visit(this, ctx);
v.endVisit(this, ctx);
}
}
@@ -22,6 +22,12 @@ public abstract class JsNumberLiteral extends JsLiteral.JsValueLiteral {
public String toString() {
return String.valueOf(value);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
v.visit(this, ctx);
v.endVisit(this, ctx);
}
}
public static final class JsIntLiteral extends JsNumberLiteral {
@@ -39,5 +45,11 @@ public abstract class JsNumberLiteral extends JsLiteral.JsValueLiteral {
public String toString() {
return String.valueOf(value);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
v.visit(this, ctx);
v.endVisit(this, ctx);
}
}
}
@@ -47,4 +47,12 @@ public final class JsObjectLiteral extends JsLiteral {
public void acceptChildren(JsVisitor visitor) {
visitor.acceptWithInsertRemove(properties);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
v.acceptList(properties);
}
v.endVisit(this, ctx);
}
}
@@ -34,4 +34,10 @@ public final class JsParameter extends SourceInfoAwareJsNode implements HasName
public void accept(JsVisitor v) {
v.visitParameter(this);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
v.visit(this, ctx);
v.endVisit(this, ctx);
}
}
@@ -17,4 +17,12 @@ public final class JsPostfixOperation extends JsUnaryOperation {
public void accept(JsVisitor v) {
v.visitPostfixOperation(this);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
super.traverse(v, ctx);
}
v.endVisit(this, ctx);
}
}
@@ -17,4 +17,12 @@ public final class JsPrefixOperation extends JsUnaryOperation {
public void accept(JsVisitor v) {
v.visitPrefixOperation(this);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
super.traverse(v, ctx);
}
v.endVisit(this, ctx);
}
}
@@ -129,4 +129,14 @@ public final class JsProgram extends SourceInfoAwareJsNode {
visitor.accept(fragment);
}
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
for (JsProgramFragment fragment : fragments) {
v.accept(fragment);
}
}
v.endVisit(this, ctx);
}
}
@@ -27,4 +27,12 @@ public class JsProgramFragment extends SourceInfoAwareJsNode {
public void acceptChildren(JsVisitor visitor) {
visitor.accept(globalBlock);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
v.accept(globalBlock);
}
v.endVisit(this, ctx);
}
}
@@ -44,4 +44,13 @@ public class JsPropertyInitializer extends SourceInfoAwareJsNode {
visitor.accept(labelExpr);
visitor.accept(valueExpr);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
labelExpr = v.accept(labelExpr);
valueExpr = v.accept(valueExpr);
}
v.endVisit(this, ctx);
}
}
@@ -31,4 +31,10 @@ public final class JsRegExp extends JsLiteral.JsValueLiteral {
public void accept(JsVisitor v) {
v.visitRegExp(this);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
v.visit(this, ctx);
v.endVisit(this, ctx);
}
}
@@ -36,4 +36,14 @@ public final class JsReturn extends SourceInfoAwareJsNode implements JsStatement
visitor.accept(expression);
}
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
if (expression != null) {
expression = v.accept(expression);
}
}
v.endVisit(this, ctx);
}
}
@@ -6,14 +6,14 @@ package com.google.dart.compiler.backend.js.ast;
public final class JsStringLiteral extends JsLiteral.JsValueLiteral {
private final String value;
private final String value;
// These only get created by JsProgram so that they can be interned.
JsStringLiteral(String value) {
// These only get created by JsProgram so that they can be interned.
JsStringLiteral(String value) {
this.value = value;
}
public String getValue() {
public String getValue() {
return value;
}
@@ -21,4 +21,10 @@ public final class JsStringLiteral extends JsLiteral.JsValueLiteral {
public void accept(JsVisitor v) {
v.visitString(this);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
v.visit(this, ctx);
v.endVisit(this, ctx);
}
}
@@ -41,4 +41,13 @@ public class JsSwitch extends SourceInfoAwareJsNode implements JsStatement {
visitor.accept(expression);
visitor.acceptWithInsertRemove(cases);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
expression = v.accept(expression);
v.acceptList(cases);
}
v.endVisit(this, ctx);
}
}
@@ -31,4 +31,12 @@ public class JsThrow extends SourceInfoAwareJsNode implements JsStatement {
public void acceptChildren(JsVisitor visitor) {
visitor.accept(expression);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
expression = v.accept(expression);
}
v.endVisit(this, ctx);
}
}
@@ -60,4 +60,16 @@ public class JsTry extends SourceInfoAwareJsNode implements JsStatement {
visitor.accept(finallyBlock);
}
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
tryBlock = v.accept(tryBlock);
v.acceptList(catches);
if (finallyBlock != null) {
finallyBlock = v.accept(finallyBlock);
}
}
v.endVisit(this, ctx);
}
}
@@ -43,4 +43,17 @@ public abstract class JsUnaryOperation extends JsExpressionImpl {
visitor.accept(arg);
}
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (op.isModifying()) {
/*
* The delete operator is practically like an assignment of undefined, so for practical
* purposes we're treating it as an lvalue.
*/
arg = v.acceptLvalue(arg);
} else {
arg = v.accept(arg);
}
}
}
@@ -88,6 +88,16 @@ public class JsVars extends SourceInfoAwareJsNode implements JsStatement, Iterab
visitor.accept(initExpression);
}
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
if (initExpression != null) {
initExpression = v.accept(initExpression);
}
}
v.endVisit(this, ctx);
}
}
public void add(JsVar var) {
@@ -126,4 +136,12 @@ public class JsVars extends SourceInfoAwareJsNode implements JsStatement, Iterab
public void acceptChildren(JsVisitor visitor) {
visitor.acceptWithInsertRemove(vars);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
v.acceptList(vars);
}
v.endVisit(this, ctx);
}
}
@@ -0,0 +1,366 @@
/*
* Copyright 2008 Google Inc.
*
* 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;
/**
* Taken from GWT project with modifications.
* Original:
* repository: https://gwt.googlesource.com/gwt
* revision: e32bf0a95029165d9e6ab457c7ee7ca8b07b908c
* file: dev/core/src/com/google/gwt/dev/js/ast/JsVisitor.java
*/
import java.util.List;
/**
* Implemented by nodes that will visit child nodes.
*/
@SuppressWarnings("UnusedParameters")
public abstract class JsVisitorWithContext {
public final <T extends JsNode> T accept(T node) {
return doAccept(node);
}
public JsExpression acceptLvalue(JsExpression expr) {
return doAcceptLvalue(expr);
}
public final <T extends JsNode> void acceptList(List<T> collection) {
doAcceptList(collection);
}
public final <T extends JsStatement> T acceptStatement(T statement) {
//noinspection unchecked
return (T) doAcceptStatement(statement);
}
public final <T extends JsStatement> void acceptStatementList(List<T> statements) {
doAcceptStatementList(statements);
}
public void endVisit(JsArrayAccess x, JsContext ctx) {
}
public void endVisit(JsArrayLiteral x, JsContext ctx) {
}
public void endVisit(JsBinaryOperation x, JsContext ctx) {
}
public void endVisit(JsBlock x, JsContext ctx) {
}
public void endVisit(JsLiteral.JsBooleanLiteral x, JsContext ctx) {
}
public void endVisit(JsBreak x, JsContext ctx) {
}
public void endVisit(JsCase x, JsContext ctx) {
}
public void endVisit(JsCatch x, JsContext ctx) {
}
public void endVisit(JsConditional x, JsContext ctx) {
}
public void endVisit(JsContinue x, JsContext ctx) {
}
public void endVisit(JsDebugger x, JsContext ctx) {
}
public void endVisit(JsDefault x, JsContext ctx) {
}
public void endVisit(JsDoWhile x, JsContext ctx) {
}
public void endVisit(JsEmpty x, JsContext ctx) {
}
public void endVisit(JsExpressionStatement x, JsContext ctx) {
}
public void endVisit(JsFor x, JsContext ctx) {
}
public void endVisit(JsForIn x, JsContext ctx) {
}
public void endVisit(JsFunction x, JsContext ctx) {
}
public void endVisit(JsIf x, JsContext ctx) {
}
public void endVisit(JsInvocation x, JsContext ctx) {
}
public void endVisit(JsLabel x, JsContext ctx) {
}
public void endVisit(JsName x, JsContext ctx) {
}
public void endVisit(JsNameRef x, JsContext ctx) {
}
public void endVisit(JsNew x, JsContext ctx) {
}
public void endVisit(JsNullLiteral x, JsContext ctx) {
}
public void endVisit(JsNumberLiteral x, JsContext ctx) {
}
public void endVisit(JsObjectLiteral x, JsContext ctx) {
}
public void endVisit(JsParameter x, JsContext ctx) {
}
public void endVisit(JsPostfixOperation x, JsContext ctx) {
}
public void endVisit(JsPrefixOperation x, JsContext ctx) {
}
public void endVisit(JsProgram x, JsContext ctx) {
}
public void endVisit(JsProgramFragment x, JsContext ctx) {
}
public void endVisit(JsPropertyInitializer x, JsContext ctx) {
}
public void endVisit(JsRegExp x, JsContext ctx) {
}
public void endVisit(JsReturn x, JsContext ctx) {
}
public void endVisit(JsStringLiteral x, JsContext ctx) {
}
public void endVisit(JsSwitch x, JsContext ctx) {
}
public void endVisit(JsLiteral.JsThisRef x, JsContext ctx) {
}
public void endVisit(JsThrow x, JsContext ctx) {
}
public void endVisit(JsTry x, JsContext ctx) {
}
public void endVisit(JsVars.JsVar x, JsContext ctx) {
}
public void endVisit(JsVars x, JsContext ctx) {
}
public void endVisit(JsWhile x, JsContext ctx) {
}
public boolean visit(JsArrayAccess x, JsContext ctx) {
return true;
}
public boolean visit(JsArrayLiteral x, JsContext ctx) {
return true;
}
public boolean visit(JsBinaryOperation x, JsContext ctx) {
return true;
}
public boolean visit(JsBlock x, JsContext ctx) {
return true;
}
public boolean visit(JsLiteral.JsBooleanLiteral x, JsContext ctx) {
return true;
}
public boolean visit(JsBreak x, JsContext ctx) {
return true;
}
public boolean visit(JsCase x, JsContext ctx) {
return true;
}
public boolean visit(JsCatch x, JsContext ctx) {
return true;
}
public boolean visit(JsConditional x, JsContext ctx) {
return true;
}
public boolean visit(JsContinue x, JsContext ctx) {
return true;
}
public boolean visit(JsDebugger x, JsContext ctx) {
return true;
}
public boolean visit(JsDefault x, JsContext ctx) {
return true;
}
public boolean visit(JsDoWhile x, JsContext ctx) {
return true;
}
public boolean visit(JsEmpty x, JsContext ctx) {
return true;
}
public boolean visit(JsExpressionStatement x, JsContext ctx) {
return true;
}
public boolean visit(JsFor x, JsContext ctx) {
return true;
}
public boolean visit(JsForIn x, JsContext ctx) {
return true;
}
public boolean visit(JsFunction x, JsContext ctx) {
return true;
}
public boolean visit(JsIf x, JsContext ctx) {
return true;
}
public boolean visit(JsInvocation x, JsContext ctx) {
return true;
}
public boolean visit(JsLabel x, JsContext ctx) {
return true;
}
public boolean visit(JsName x, JsContext ctx) {
return true;
}
public boolean visit(JsNameRef x, JsContext ctx) {
return true;
}
public boolean visit(JsNew x, JsContext ctx) {
return true;
}
public boolean visit(JsNullLiteral x, JsContext ctx) {
return true;
}
public boolean visit(JsNumberLiteral x, JsContext ctx) {
return true;
}
public boolean visit(JsObjectLiteral x, JsContext ctx) {
return true;
}
public boolean visit(JsParameter x, JsContext ctx) {
return true;
}
public boolean visit(JsPostfixOperation x, JsContext ctx) {
return true;
}
public boolean visit(JsPrefixOperation x, JsContext ctx) {
return true;
}
public boolean visit(JsProgram x, JsContext ctx) {
return true;
}
public boolean visit(JsProgramFragment x, JsContext ctx) {
return true;
}
public boolean visit(JsPropertyInitializer x, JsContext ctx) {
return true;
}
public boolean visit(JsRegExp x, JsContext ctx) {
return true;
}
public boolean visit(JsReturn x, JsContext ctx) {
return true;
}
public boolean visit(JsStringLiteral x, JsContext ctx) {
return true;
}
public boolean visit(JsSwitch x, JsContext ctx) {
return true;
}
public boolean visit(JsLiteral.JsThisRef x, JsContext ctx) {
return true;
}
public boolean visit(JsThrow x, JsContext ctx) {
return true;
}
public boolean visit(JsTry x, JsContext ctx) {
return true;
}
public boolean visit(JsVars.JsVar x, JsContext ctx) {
return true;
}
public boolean visit(JsVars x, JsContext ctx) {
return true;
}
public boolean visit(JsWhile x, JsContext ctx) {
return true;
}
protected abstract <T extends JsNode> T doAccept(T node);
protected abstract JsExpression doAcceptLvalue(JsExpression expr);
protected abstract <T extends JsNode> void doAcceptList(List<T> collection);
protected abstract <T extends JsStatement> JsStatement doAcceptStatement(T statement);
protected abstract <T extends JsStatement> void doAcceptStatementList(List<T> statements);
protected abstract <T extends JsNode> void doTraverse(T node, JsContext ctx) ;
}
@@ -0,0 +1,210 @@
/*
* Copyright 2008 Google Inc.
*
* 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;
/**
* Taken from GWT project with modifications.
* Original:
* repository: https://gwt.googlesource.com/gwt
* revision: e32bf0a95029165d9e6ab457c7ee7ca8b07b908c
* file: dev/core/src/com/google/gwt/dev/js/ast/JsModVisitor.java
*/
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Stack;
/**
* A visitor for iterating through and modifying an AST.
*/
public class JsVisitorWithContextImpl extends JsVisitorWithContext {
private final Stack<JsContext> statementContexts = new Stack<JsContext>();
public class ListContext<T extends JsNode> implements JsContext {
private List<T> collection;
private int index;
@Override
public boolean canInsert() {
return true;
}
@Override
public boolean canRemove() {
return true;
}
@Override
public void insertAfter(JsNode node) {
//noinspection unchecked
collection.add(index + 1, (T) node);
}
@Override
public void insertBefore(JsNode node) {
//noinspection unchecked
collection.add(index++, (T) node);
}
@Override
public boolean isLvalue() {
return false;
}
@Override
public void removeMe() {
collection.remove(index--);
}
@Override
public void replaceMe(JsNode node) {
checkReplacement(collection.get(index), node);
//noinspection unchecked
collection.set(index, (T) node);
}
@Nullable
@Override
public JsNode getCurrentNode() {
if (index < collection.size()) {
return collection.get(index);
}
return null;
}
protected void traverse(List<T> collection) {
this.collection = collection;
for (index = 0; index < collection.size(); ++index) {
T node = collection.get(index);
doTraverse(node, this);
}
}
}
private class LvalueContext extends NodeContext<JsExpression> {
@Override
public boolean isLvalue() {
return true;
}
}
@SuppressWarnings("unchecked")
private class NodeContext<T extends JsNode> implements JsContext {
protected T node;
@Override
public boolean canInsert() {
return false;
}
@Override
public boolean canRemove() {
return false;
}
@Override
public void insertAfter(JsNode node) {
throw new UnsupportedOperationException();
}
@Override
public void insertBefore(JsNode node) {
throw new UnsupportedOperationException();
}
@Override
public boolean isLvalue() {
return false;
}
@Override
public void removeMe() {
throw new UnsupportedOperationException();
}
@Override
public void replaceMe(JsNode node) {
checkReplacement(this.node, node);
this.node = (T) node;
}
@Nullable
@Override
public JsNode getCurrentNode() {
return node;
}
protected T traverse(T node) {
this.node = node;
doTraverse(node, this);
return this.node;
}
}
protected static void checkReplacement(@SuppressWarnings("UnusedParameters") JsNode origNode, JsNode newNode) {
if (newNode == null) throw new RuntimeException("Cannot replace with null");
}
@Override
protected <T extends JsNode> T doAccept(T node) {
return new NodeContext<T>().traverse(node);
}
@Override
protected JsExpression doAcceptLvalue(JsExpression expr) {
return new LvalueContext().traverse(expr);
}
@Override
protected <T extends JsStatement> JsStatement doAcceptStatement(T statement) {
List<JsStatement> statements = new SmartList<JsStatement>(statement);
doAcceptStatementList(statements);
if (statements.size() == 1) {
return statements.get(0);
}
return new JsBlock(statements);
}
@Override
protected <T extends JsStatement> void doAcceptStatementList(List<T> statements) {
ListContext<T> context = new ListContext<T>();
statementContexts.push(context);
context.traverse(statements);
statementContexts.pop();
}
@Override
protected <T extends JsNode> void doAcceptList(List<T> collection) {
new ListContext<T>().traverse(collection);
}
@NotNull
protected JsContext getLastStatementLevelContext() {
return statementContexts.peek();
}
@Override
protected <T extends JsNode> void doTraverse(T node, JsContext ctx) {
node.traverse(this, ctx);
}
}
@@ -45,4 +45,13 @@ public class JsWhile extends SourceInfoAwareJsNode implements JsStatement {
visitor.accept(condition);
visitor.accept(body);
}
@Override
public void traverse(JsVisitorWithContext v, JsContext ctx) {
if (v.visit(this, ctx)) {
condition = v.accept(condition);
body = v.acceptStatement(body);
}
v.endVisit(this, ctx);
}
}