1 /*
2  * [The "BSD license"]
3  *  Copyright (c) 2012 Terence Parr
4  *  Copyright (c) 2012 Sam Harwell
5  *  Copyright (c) 2012 Egbert Voigt
6  *  All rights reserved.
7  *
8  *  Redistribution and use in source and binary forms, with or without
9  *  modification, are permitted provided that the following conditions
10  *  are met:
11  *
12  *  1. Redistributions of source code must retain the above copyright
13  *     notice, this list of conditions and the following disclaimer.
14  *  2. Redistributions in binary form must reproduce the above copyright
15  *     notice, this list of conditions and the following disclaimer in the
16  *     documentation and/or other materials provided with the distribution.
17  *  3. The name of the author may not be used to endorse or promote products
18  *     derived from this software without specific prior written permission.
19  *
20  *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 module antlr.v4.runtime.ANTLRInputStream;
33 
34 import antlr.v4.runtime.CharStream;
35 import antlr.v4.runtime.IntStream;
36 import antlr.v4.runtime.IntStreamConstant;
37 import antlr.v4.runtime.misc.Interval;
38 import std.algorithm;
39 import std.conv;
40 import std.file;
41 import std.format;
42 import std.stdio;
43 
44 /**
45  * Vacuum all input from a {@link Reader}/{@link InputStream} and then treat it
46  * like a {@code char[]} buffer. Can also pass in a {@link String} or
47  * {@code char[]} to use.
48  *
49  * <p>If you need encoding, pass in stream/reader with correct encoding.</p>
50  */
51 class ANTLRInputStream : CharStream
52 {
53 
54     public static int READ_BUFFER_SIZE = 1024;
55 
56     public static int INITIAL_BUFFER_SIZE = 1024;;
57 
58     /**
59      * @uml
60      * The data being scanned
61      */
62     protected char[] data;
63 
64     /**
65      * @uml
66      * How many characters are actually in the buffer
67      */
68     protected int n;
69 
70     /**
71      * @uml
72      * 0..n-1 index into string of next char
73      */
74     protected int p = 0;
75 
76     /**
77      * @uml
78      * What is name or source of this char stream?
79      */
80     public string name;
81 
82     public this()
83     {
84     }
85 
86     /**
87      * @uml
88      * Copy data in string to a local char array
89      */
90     public this(string input)
91     {
92         this.data = input.to!(char []);
93         this.n = to!int(input.length);
94     }
95 
96     /**
97      * @uml
98      * This is the preferred constructor for strings as no data is copied
99      */
100     public this(char[] data, int numberOfActualCharsInArray)
101     {
102         this.data = data;
103         this.n = numberOfActualCharsInArray;
104     }
105 
106     public this(File r)
107     {
108         load(r, INITIAL_BUFFER_SIZE, READ_BUFFER_SIZE);
109     }
110 
111     public void load(File r, int size, int readChunkSize)
112     {
113         debug(ANTLRInput)
114             writefln("load %1$s in chunks of %2$s", size, readChunkSize);
115         data = to!(char[])(r.name.readText);
116         // set the actual size of the data available;
117         n = to!int(data.length);
118         debug(ANTLRInput)
119             writefln("n= $s", n);
120     }
121 
122     /**
123      * @uml
124      * Reset the stream so that it's in the same state it was
125      * when the object was created *except* the data array is not
126      * touched.
127      */
128     public void reset()
129     {
130         p = 0;
131     }
132 
133     /**
134      * @uml
135      * @override
136      */
137     public override void consume()
138     {
139 	if (p >= n) {
140             assert (LA(1) == IntStreamConstant.EOF, "cannot consume EOF");
141         }
142         //System.out.println("prev p="+p+", c="+(char)data[p]);
143         if (p < n) {
144             p++;
145             //System.out.println("p moves to "+p+" (c='"+(char)data[p]+"')");
146         }
147     }
148 
149     /**
150      * @uml
151      * @override
152      */
153     public override int LA(int i)
154     {
155         if (i == 0) {
156             return 0; // undefined
157         }
158         if (i < 0) {
159             i++; // e.g., translate LA(-1) to use offset i=0; then data[p+0-1]
160             if ((p + i - 1) < 0) {
161                 return IntStreamConstant.EOF; // invalid; no char before first char
162             }
163         }
164         if (( p + i - 1) >= n) {
165             debug(ANTLRInput) {
166                 import std.stdio;
167                 writefln("char LA(%s)=EOF; p=%s", i, p);
168             }
169             return IntStreamConstant.EOF;
170         }
171         debug(ANTLRInput) {
172                 import std.stdio;
173                 writefln("LA(%s); p=%s n=%s data.length=%s", i, p, n, data.length);
174                 writefln("char LA(%s)=%s; p=%s", i, data[p+i-1], p);
175             }
176         return data[p+i-1];
177     }
178 
179     public int LT(int i)
180     {
181         return LA(i);
182     }
183 
184     /**
185      * @uml
186      * @override
187      */
188     public override int index()
189     {
190         return p;
191     }
192 
193     /**
194      * @uml
195      * @override
196      */
197     public override int size()
198     {
199         return n;
200     }
201 
202     /**
203      * @uml
204      * mark/release do nothing; we have entire buffer
205      * @override
206      */
207     public override int mark()
208     {
209         return -1;
210     }
211 
212     /**
213      * @uml
214      * @override
215      */
216     public override void release(int marker)
217     {
218     }
219 
220     /**
221      * @uml
222      * consume() ahead until p==index; can't just set p=index as we must
223      * update line and charPositionInLine. If we seek backwards, just set p
224      * @override
225      */
226     public override void seek(int index)
227     {
228 	if (index <= p) {
229             p = index; // just jump; don't update stream state (line, ...)
230             return;
231         }
232         // seek forward, consume until p hits index or n (whichever comes first)
233         index = min(index, n);
234         while (p < index) {
235             consume();
236         }
237     }
238 
239     /**
240      * @uml
241      * @override
242      */
243     public override string getText(Interval interval)
244     {
245         int start = interval.a;
246         int stop = interval.b;
247         if (stop >= n)
248             stop = n-1;
249         if (start >= n) return "";
250         //		System.err.println("data: "+Arrays.toString(data)+", n="+n+
251         //						   ", start="+start+
252         //						   ", stop="+stop);
253         return to!string(data[start..stop+1]);
254     }
255 
256     /**
257      * @uml
258      * @override
259      */
260     public override string getSourceName()
261     {
262         if (name is null || name.length == 0) {
263             return IntStreamConstant.UNKNOWN_SOURCE_NAME;
264         }
265         return name;
266     }
267 
268     /**
269      * @uml
270      * @override
271      */
272     public override string toString()
273     {
274         return to!string(data);
275     }
276 
277 }