1/*
2 * [The "BSD licence"]
3 * Copyright (c) 2005-2008 Terence Parr
4 * All rights reserved.
5 *
6 * Conversion to C#:
7 * Copyright (c) 2008-2009 Sam Harwell, Pixel Mine, Inc.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. The name of the author may not be used to endorse or promote products
19 *    derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33namespace Antlr.Runtime.Tree {
34    using ArgumentNullException = System.ArgumentNullException;
35    using CLSCompliant = System.CLSCompliantAttribute;
36
37    /** <summary>
38     *  A tree node that is wrapper for a Token object.  After 3.0 release
39     *  while building tree rewrite stuff, it became clear that computing
40     *  parent and child index is very difficult and cumbersome.  Better to
41     *  spend the space in every tree node.  If you don't want these extra
42     *  fields, it's easy to cut them out in your own BaseTree subclass.
43     *  </summary>
44     */
45    [System.Serializable]
46    public class CommonTree : BaseTree {
47        /** <summary>A single token is the payload</summary> */
48        [CLSCompliant(false)]
49        public IToken token;
50
51        /** <summary>
52         *  What token indexes bracket all tokens associated with this node
53         *  and below?
54         *  </summary>
55         */
56        protected int startIndex = -1;
57        protected int stopIndex = -1;
58
59        /** <summary>Who is the parent node of this node; if null, implies node is root</summary> */
60        CommonTree parent;
61
62        /** <summary>What index is this node in the child list? Range: 0..n-1</summary> */
63        int childIndex = -1;
64
65        public CommonTree() {
66        }
67
68        public CommonTree(CommonTree node)
69            : base(node) {
70            if (node == null)
71                throw new ArgumentNullException("node");
72
73            this.token = node.token;
74            this.startIndex = node.startIndex;
75            this.stopIndex = node.stopIndex;
76        }
77
78        public CommonTree(IToken t) {
79            this.token = t;
80        }
81
82        #region Properties
83        public override int CharPositionInLine {
84            get {
85                if (token == null || token.CharPositionInLine == -1) {
86                    if (ChildCount > 0) {
87                        return Children[0].CharPositionInLine;
88                    }
89                    return 0;
90                }
91                return token.CharPositionInLine;
92            }
93            set {
94                base.CharPositionInLine = value;
95            }
96        }
97        public override int ChildIndex {
98            get {
99                return childIndex;
100            }
101            set {
102                childIndex = value;
103            }
104        }
105        public override bool IsNil {
106            get {
107                return token == null;
108            }
109        }
110        public override int Line {
111            get {
112                if (token == null || token.Line == 0) {
113                    if (ChildCount > 0) {
114                        return Children[0].Line;
115                    }
116                    return 0;
117                }
118                return token.Line;
119            }
120            set {
121                base.Line = value;
122            }
123        }
124        public override ITree Parent {
125            get {
126                return parent;
127            }
128            set {
129                parent = (CommonTree)value;
130            }
131        }
132        public override string Text {
133            get {
134                if (token == null)
135                    return null;
136
137                return token.Text;
138            }
139            set {
140            }
141        }
142        public virtual IToken Token {
143            get {
144                return token;
145            }
146            set {
147                token = value;
148            }
149        }
150        public override int TokenStartIndex {
151            get {
152                if (startIndex == -1 && token != null) {
153                    return token.TokenIndex;
154                }
155                return startIndex;
156            }
157            set {
158                startIndex = value;
159            }
160        }
161        public override int TokenStopIndex {
162            get {
163                if (stopIndex == -1 && token != null) {
164                    return token.TokenIndex;
165                }
166                return stopIndex;
167            }
168            set {
169                stopIndex = value;
170            }
171        }
172        public override int Type {
173            get {
174                if (token == null)
175                    return TokenTypes.Invalid;
176
177                return token.Type;
178            }
179            set {
180            }
181        }
182        #endregion
183
184        public override ITree DupNode() {
185            return new CommonTree(this);
186        }
187
188        /** <summary>
189         *  For every node in this subtree, make sure it's start/stop token's
190         *  are set.  Walk depth first, visit bottom up.  Only updates nodes
191         *  with at least one token index &lt; 0.
192         *  </summary>
193         */
194        public virtual void SetUnknownTokenBoundaries() {
195            if (Children == null) {
196                if (startIndex < 0 || stopIndex < 0) {
197                    startIndex = stopIndex = token.TokenIndex;
198                }
199                return;
200            }
201            for (int i = 0; i < Children.Count; i++) {
202                ((CommonTree)Children[i]).SetUnknownTokenBoundaries();
203            }
204            if (startIndex >= 0 && stopIndex >= 0)
205                return; // already set
206            if (Children.Count > 0) {
207                CommonTree firstChild = (CommonTree)Children[0];
208                CommonTree lastChild = (CommonTree)Children[Children.Count - 1];
209                startIndex = firstChild.TokenStartIndex;
210                stopIndex = lastChild.TokenStopIndex;
211            }
212        }
213
214        public override string ToString() {
215            if (IsNil) {
216                return "nil";
217            }
218            if (Type == TokenTypes.Invalid) {
219                return "<errornode>";
220            }
221            if (token == null) {
222                return string.Empty;
223            }
224            return token.Text;
225        }
226    }
227}
228