001: /*
002: * Copyright 2007 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package com.google.gwt.dev.js.ast;
017:
018: import com.google.gwt.dev.jjs.InternalCompilerException;
019:
020: import java.util.List;
021:
022: /**
023: * A visitor for iterating through and modifying an AST.
024: */
025: public class JsModVisitor extends JsVisitor {
026:
027: private class ListContext<T extends JsVisitable<T>> implements
028: JsContext<T> {
029: private List<T> collection;
030: private int index;
031: private boolean removed;
032: private boolean replaced;
033:
034: public boolean canInsert() {
035: return true;
036: }
037:
038: public boolean canRemove() {
039: return true;
040: }
041:
042: public void insertAfter(T node) {
043: checkRemoved();
044: collection.add(index + 1, node);
045: didChange = true;
046: }
047:
048: public void insertBefore(T node) {
049: checkRemoved();
050: collection.add(index++, node);
051: didChange = true;
052: }
053:
054: public void removeMe() {
055: checkState();
056: collection.remove(index--);
057: didChange = removed = true;
058: }
059:
060: public void replaceMe(T node) {
061: checkState();
062: checkReplacement(collection.get(index), node);
063: collection.set(index, node);
064: didChange = replaced = true;
065: }
066:
067: protected void traverse(List<T> collection) {
068: this .collection = collection;
069: for (index = 0; index < collection.size(); ++index) {
070: removed = replaced = false;
071: doTraverse(collection.get(index), this );
072: }
073: }
074:
075: private void checkRemoved() {
076: if (removed) {
077: throw new InternalCompilerException(
078: "Node was already removed");
079: }
080: }
081:
082: private void checkState() {
083: checkRemoved();
084: if (replaced) {
085: throw new InternalCompilerException(
086: "Node was already replaced");
087: }
088: }
089: }
090:
091: private class NodeContext<T extends JsVisitable<T>> implements
092: JsContext<T> {
093: private T node;
094: private boolean replaced;
095:
096: public boolean canInsert() {
097: return false;
098: }
099:
100: public boolean canRemove() {
101: return false;
102: }
103:
104: public void insertAfter(T node) {
105: throw new UnsupportedOperationException();
106: }
107:
108: public void insertBefore(T node) {
109: throw new UnsupportedOperationException();
110: }
111:
112: public void removeMe() {
113: throw new UnsupportedOperationException();
114: }
115:
116: public void replaceMe(T node) {
117: if (replaced) {
118: throw new InternalCompilerException(
119: "Node was already replaced");
120: }
121: checkReplacement(this .node, node);
122: this .node = node;
123: didChange = replaced = true;
124: }
125:
126: protected T traverse(T node) {
127: this .node = node;
128: replaced = false;
129: doTraverse(node, this );
130: return this .node;
131: }
132: }
133:
134: protected static <T extends JsVisitable<T>> void checkReplacement(
135: T origNode, T newNode) {
136: if (newNode == null) {
137: throw new InternalCompilerException(
138: "Cannot replace with null");
139: }
140: if (newNode == origNode) {
141: throw new InternalCompilerException(
142: "The replacement is the same as the original");
143: }
144: }
145:
146: protected boolean didChange = false;
147:
148: @Override
149: public boolean didChange() {
150: return didChange;
151: }
152:
153: @Override
154: protected <T extends JsVisitable<T>> T doAccept(T node) {
155: return new NodeContext<T>().traverse(node);
156: }
157:
158: @Override
159: protected <T extends JsVisitable<T>> void doAcceptList(
160: List<T> collection) {
161: for (int i = 0, c = collection.size(); i < c; ++i) {
162: collection.set(i, new NodeContext<T>().traverse(collection
163: .get(i)));
164: }
165: }
166:
167: @Override
168: protected <T extends JsVisitable<T>> void doAcceptWithInsertRemove(
169: List<T> collection) {
170: new ListContext<T>().traverse(collection);
171: }
172:
173: }
|