1/*
2 [The "BSD licence"]
3 Copyright (c) 2005-2006 Terence Parr
4 All rights reserved.
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
9 1. Redistributions of source code must retain the above copyright
10    notice, this list of conditions and the following disclaimer.
11 2. Redistributions in binary form must reproduce the above copyright
12    notice, this list of conditions and the following disclaimer in the
13    documentation and/or other materials provided with the distribution.
14 3. The name of the author may not be used to endorse or promote products
15    derived from this software without specific prior written permission.
16
17 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27*/
28package org.antlr.runtime {
29
30	public class ANTLRStringStream implements CharStream {
31		/** The data being scanned */
32		protected var data:String;
33
34		/** How many characters are actually in the buffer */
35		protected var n:int;
36
37		/** 0..n-1 index into string of next char */
38		protected var p:int = 0;
39
40		/** line number 1..n within the input */
41		protected var _line:int = 1;
42
43		/** The index of the character relative to the beginning of the line 0..n-1 */
44		protected var _charPositionInLine:int = 0;
45
46		/** tracks how deep mark() calls are nested */
47		protected var markDepth:int = 0;
48
49		/** A list of CharStreamState objects that tracks the stream state
50		 *  values line, charPositionInLine, and p that can change as you
51		 *  move through the input stream.  Indexed from 1..markDepth.
52	     *  A null is kept @ index 0.  Create upon first call to mark().
53		 */
54		protected var markers:Array;
55
56		/** Track the last mark() call result value for use in rewind(). */
57		protected var lastMarker:int;
58
59		protected var _sourceName:String;
60
61	    protected var _lineDelimiter:String;
62
63		/** Copy data in string to a local char array */
64		public function ANTLRStringStream(input:String = null, lineDelimiter:String = "\n") {
65			this._lineDelimiter = lineDelimiter;
66			if (input != null) {
67				this.data = input;
68				this.n = input.length;
69			}
70		}
71
72		/** Reset the stream so that it's in the same state it was
73		 *  when the object was created *except* the data array is not
74		 *  touched.
75		 */
76		public function reset():void {
77			p = 0;
78			_line = 1;
79			_charPositionInLine = 0;
80			markDepth = 0;
81		}
82
83	    public function consume():void {
84	        if ( p < n ) {
85				_charPositionInLine++;
86				if ( data.charAt(p)==_lineDelimiter ) {
87					_line++;
88					_charPositionInLine=0;
89				}
90	            p++;
91	        }
92	    }
93
94	    public function LA(i:int):int {
95			if ( i==0 ) {
96				return 0; // undefined
97			}
98			if ( i<0 ) {
99				i++; // e.g., translate LA(-1) to use offset i=0; then data[p+0-1]
100				if ( (p+i-1) < 0 ) {
101					return CharStreamConstants.EOF; // invalid; no char before first char
102				}
103			}
104
105			if ( (p+i-1) >= n ) {
106	            return CharStreamConstants.EOF;
107	        }
108			return data.charCodeAt(p+i-1);
109	    }
110
111		public function LT(i:int):int {
112			return LA(i);
113		}
114
115		/** Return the current input symbol index 0..n where n indicates the
116	     *  last symbol has been read.  The index is the index of char to
117		 *  be returned from LA(1).
118	     */
119	    public function get index():int {
120	        return p;
121	    }
122
123		public function get size():int {
124			return n;
125		}
126
127		public function mark():int {
128	        if ( markers==null ) {
129	            markers = new Array();
130	            markers.push(null); // depth 0 means no backtracking, leave blank
131	        }
132	        markDepth++;
133			var state:CharStreamState = null;
134			if ( markDepth>=markers.length ) {
135				state = new CharStreamState();
136				markers.push(state);
137			}
138			else {
139				state = CharStreamState(markers[markDepth]);
140			}
141			state.p = p;
142			state.line = _line;
143			state.charPositionInLine = _charPositionInLine;
144			lastMarker = markDepth;
145			return markDepth;
146	    }
147
148	    public function rewindTo(m:int):void {
149			var state:CharStreamState = CharStreamState(markers[m]);
150			// restore stream state
151			seek(state.p);
152			_line = state.line;
153			_charPositionInLine = state.charPositionInLine;
154			release(m);
155		}
156
157		public function rewind():void {
158			rewindTo(lastMarker);
159		}
160
161		public function release(marker:int):void {
162			// unwind any other markers made after m and release m
163			markDepth = marker;
164			// release this marker
165			markDepth--;
166		}
167
168		/** consume() ahead until p==index; can't just set p=index as we must
169		 *  update line and charPositionInLine.
170		 */
171		public function seek(index:int):void {
172			if ( index<=p ) {
173				p = index; // just jump; don't update stream state (line, ...)
174				return;
175			}
176			// seek forward, consume until p hits index
177			while ( p<index ) {
178				consume();
179			}
180		}
181
182		public function substring(start:int, stop:int):String {
183			return data.substring(start, stop + 1);
184		}
185
186		public function get line():int {
187			return _line;
188		}
189
190		public function get charPositionInLine():int {
191			return _charPositionInLine;
192		}
193
194		public function set line(line:int):void {
195			this._line = line;
196		}
197
198		public function set charPositionInLine(pos:int):void {
199			this._charPositionInLine = pos;
200		}
201
202		public function get sourceName():String {
203			return _sourceName;
204		}
205
206		public function set sourceName(sourceName:String):void {
207			_sourceName = sourceName;
208		}
209
210	}
211
212}