1/** A TreeAdaptor that works with any Tree implementation. */
2org.antlr.runtime.tree.BaseTreeAdaptor = function() {
3    this.uniqueNodeID = 1;
4};
5org.antlr.runtime.tree.TreeAdaptor = function() {};
6
7org.antlr.lang.extend(org.antlr.runtime.tree.BaseTreeAdaptor,
8                      org.antlr.runtime.tree.TreeAdaptor,
9{
10    nil: function() {
11        return this.create(null);
12    },
13
14    /** create tree node that holds the start and stop tokens associated
15     *  with an error.
16     *
17     *  If you specify your own kind of tree nodes, you will likely have to
18     *  override this method. CommonTree returns Token.INVALID_TOKEN_TYPE
19     *  if no token payload but you might have to set token type for diff
20     *  node type.
21     */
22    errorNode: function(input, start, stop, e) {
23        var t = new org.antlr.runtime.tree.CommonErrorNode(input, start, stop, e);
24        return t;
25    },
26
27    isNil: function(tree) {
28        return tree.isNil();
29    },
30
31    /** This is generic in the sense that it will work with any kind of
32     *  tree (not just Tree interface).  It invokes the adaptor routines
33     *  not the tree node routines to do the construction.
34     */
35    dupTree: function(t, parent) {
36        if (arguments.length===1) {
37            parent = null;
38        }
39        if ( !t ) {
40            return null;
41        }
42        var newTree = this.dupNode(t);
43        // ensure new subtree root has parent/child index set
44        this.setChildIndex(newTree, this.getChildIndex(t)); // same index in new tree
45        this.setParent(newTree, parent);
46        var n = this.getChildCount(t),
47            i, child, newSubTree;
48        for (i = 0; i < n; i++) {
49            child = this.getChild(t, i);
50            newSubTree = this.dupTree(child, t);
51            this.addChild(newTree, newSubTree);
52        }
53        return newTree;
54    },
55
56    /** Add a child to the tree t.  If child is a flat tree (a list), make all
57     *  in list children of t.  Warning: if t has no children, but child does
58     *  and child isNil then you can decide it is ok to move children to t via
59     *  t.children = child.children; i.e., without copying the array.  Just
60     *  make sure that this is consistent with have the user will build
61     *  ASTs.
62     */
63    addChild: function(t, child) {
64        if ( t && org.antlr.lang.isValue(child) ) {
65            t.addChild(child);
66        }
67    },
68
69    /** If oldRoot is a nil root, just copy or move the children to newRoot.
70     *  If not a nil root, make oldRoot a child of newRoot.
71     *
72     *    old=^(nil a b c), new=r yields ^(r a b c)
73     *    old=^(a b c), new=r yields ^(r ^(a b c))
74     *
75     *  If newRoot is a nil-rooted single child tree, use the single
76     *  child as the new root node.
77     *
78     *    old=^(nil a b c), new=^(nil r) yields ^(r a b c)
79     *    old=^(a b c), new=^(nil r) yields ^(r ^(a b c))
80     *
81     *  If oldRoot was null, it's ok, just return newRoot (even if isNil).
82     *
83     *    old=null, new=r yields r
84     *    old=null, new=^(nil r) yields ^(nil r)
85     *
86     *  Return newRoot.  Throw an exception if newRoot is not a
87     *  simple node or nil root with a single child node--it must be a root
88     *  node.  If newRoot is ^(nil x) return x as newRoot.
89     *
90     *  Be advised that it's ok for newRoot to point at oldRoot's
91     *  children; i.e., you don't have to copy the list.  We are
92     *  constructing these nodes so we should have this control for
93     *  efficiency.
94     */
95    becomeRoot: function(newRoot, oldRoot) {
96        if (newRoot instanceof org.antlr.runtime.Token || !newRoot) {
97            newRoot = this.create(newRoot);
98        }
99
100        var newRootTree = newRoot,
101            oldRootTree = oldRoot;
102        if ( !oldRoot ) {
103            return newRoot;
104        }
105        // handle ^(nil real-node)
106        if ( newRootTree.isNil() ) {
107            var nc = newRootTree.getChildCount();
108            if (nc===1) {
109                newRootTree = newRootTree.getChild(0);
110            } else if ( nc>1 ) {
111                // TODO: make tree run time exceptions hierarchy
112                throw new Error("more than one node as root (TODO: make exception hierarchy)");
113            }
114        }
115        // add oldRoot to newRoot; addChild takes care of case where oldRoot
116        // is a flat list (i.e., nil-rooted tree).  All children of oldRoot
117        // are added to newRoot.
118        newRootTree.addChild(oldRootTree);
119        return newRootTree;
120    },
121
122    /** Transform ^(nil x) to x */
123    rulePostProcessing: function(root) {
124        var r = root;
125        if ( r && r.isNil() ) {
126            if ( r.getChildCount()===0 ) {
127                r = null;
128            }
129            else if ( r.getChildCount()===1 ) {
130                r = r.getChild(0);
131                // whoever invokes rule will set parent and child index
132                r.setParent(null);
133                r.setChildIndex(-1);
134            }
135        }
136        return r;
137    },
138
139    create: function(tokenType, fromToken) {
140        var text, t;
141        if (arguments.length===2) {
142            if (org.antlr.lang.isString(arguments[1])) {
143                text = arguments[1];
144                fromToken = this.createToken(tokenType, text);
145                t = this.create(fromToken);
146                return t;
147            } else {
148                fromToken = this.createToken(fromToken);
149                fromToken.setType(tokenType);
150                t = this.create(fromToken);
151                return t;
152            }
153        } else if (arguments.length===3) {
154            text = arguments[2];
155            fromToken = this.createToken(fromToken);
156            fromToken.setType(tokenType);
157            fromToken.setText(text);
158            t = this.create(fromToken);
159            return t;
160        }
161    },
162
163    getType: function(t) {
164        t.getType();
165        return 0;
166    },
167
168    setType: function(t, type) {
169        throw new Error("don't know enough about Tree node");
170    },
171
172    getText: function(t) {
173        return t.getText();
174    },
175
176    setText: function(t, text) {
177        throw new Error("don't know enough about Tree node");
178    },
179
180    getChild: function(t, i) {
181        return t.getChild(i);
182    },
183
184    setChild: function(t, i, child) {
185        t.setChild(i, child);
186    },
187
188    deleteChild: function(t, i) {
189        return t.deleteChild(i);
190    },
191
192    getChildCount: function(t) {
193        return t.getChildCount();
194    },
195
196    getUniqueID: function(node) {
197        if ( !this.treeToUniqueIDMap ) {
198             this.treeToUniqueIDMap = {};
199        }
200        var prevID = this.treeToUniqueIDMap[node];
201        if ( org.antlr.lang.isValue(prevID) ) {
202            return prevID;
203        }
204        var ID = this.uniqueNodeID;
205        this.treeToUniqueIDMap[node] = ID;
206        this.uniqueNodeID++;
207        return ID;
208        // GC makes these nonunique:
209        // return System.identityHashCode(node);
210    }
211});
212