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 // Class ANTLRInputStream
45 /**
46  * Vacuum all input from a {@link Reader}/{@link InputStream} and then treat it
47  * like a {@code char[]} buffer. Can also pass in a {@link String} or
48  * {@code char[]} to use.
49  *
50  * <p>If you need encoding, pass in stream/reader with correct encoding.</p>
51  */
52 class ANTLRInputStream : CharStream
53 {
54 
55     public static int READ_BUFFER_SIZE = 1024;
56 
57     public static int INITIAL_BUFFER_SIZE = 1024;;
58 
59     /**
60      * @uml
61      * The data being scanned
62      */
63     protected char[] data;
64 
65     /**
66      * @uml
67      * How many characters are actually in the buffer
68      */
69     protected int n;
70 
71     /**
72      * @uml
73      * 0..n-1 index into string of next char
74      */
75     protected int p = 0;
76 
77     /**
78      * @uml
79      * What is name or source of this char stream?
80      */
81     public string name;
82 
83     public this()
84     {
85     }
86 
87     /**
88      * @uml
89      * Copy data in string to a local char array
90      */
91     public this(string input)
92     {
93         this.data = input.to!(char []);
94         this.n = to!int(input.length);
95     }
96 
97     /**
98      * @uml
99      * This is the preferred constructor for strings as no data is copied
100      */
101     public this(char[] data, int numberOfActualCharsInArray)
102     {
103         this.data = data;
104         this.n = numberOfActualCharsInArray;
105     }
106 
107     public this(File r)
108     {
109         load(r, INITIAL_BUFFER_SIZE, READ_BUFFER_SIZE);
110     }
111 
112     public void load(File r, int size, int readChunkSize)
113     {
114         debug(ANTLRInput)
115             writefln("load %1$s in chunks of %2$s", size, readChunkSize);
116         data = to!(char[])(r.name.readText);
117         // set the actual size of the data available;
118         n = to!int(data.length);
119         debug(ANTLRInput)
120             writefln("n= $s", n);
121     }
122 
123     /**
124      * @uml
125      * Reset the stream so that it's in the same state it was
126      * when the object was created *except* the data array is not
127      * touched.
128      */
129     public void reset()
130     {
131         p = 0;
132     }
133 
134     /**
135      * @uml
136      * @override
137      */
138     public override void consume()
139     {
140 	if (p >= n) {
141             assert (LA(1) == IntStreamConstant.EOF, "cannot consume EOF");
142         }
143         //System.out.println("prev p="+p+", c="+(char)data[p]);
144         if (p < n) {
145             p++;
146             //System.out.println("p moves to "+p+" (c='"+(char)data[p]+"')");
147         }
148     }
149 
150     /**
151      * @uml
152      * @override
153      */
154     public override int LA(int i)
155     {
156         if (i == 0) {
157             return 0; // undefined
158         }
159         if (i < 0) {
160             i++; // e.g., translate LA(-1) to use offset i=0; then data[p+0-1]
161             if ((p + i - 1) < 0) {
162                 return IntStreamConstant.EOF; // invalid; no char before first char
163             }
164         }
165         if (( p + i - 1) >= n) {
166             debug(ANTLRInput) {
167                 import std.stdio;
168                 writefln("char LA(%s)=EOF; p=%s", i, p);
169             }
170             return IntStreamConstant.EOF;
171         }
172         debug(ANTLRInput) {
173                 import std.stdio;
174                 writefln("LA(%s); p=%s n=%s data.length=%s", i, p, n, data.length);
175                 writefln("char LA(%s)=%s; p=%s", i, data[p+i-1], p);
176             }
177         return data[p+i-1];
178     }
179 
180     public int LT(int i)
181     {
182         return LA(i);
183     }
184 
185     /**
186      * @uml
187      * @override
188      */
189     public override int index()
190     {
191         return p;
192     }
193 
194     /**
195      * @uml
196      * @override
197      */
198     public override int size()
199     {
200         return n;
201     }
202 
203     /**
204      * @uml
205      * mark/release do nothing; we have entire buffer
206      * @override
207      */
208     public override int mark()
209     {
210         return -1;
211     }
212 
213     /**
214      * @uml
215      * @override
216      */
217     public override void release(int marker)
218     {
219     }
220 
221     /**
222      * @uml
223      * consume() ahead until p==index; can't just set p=index as we must
224      * update line and charPositionInLine. If we seek backwards, just set p
225      * @override
226      */
227     public override void seek(int index)
228     {
229 	if (index <= p) {
230             p = index; // just jump; don't update stream state (line, ...)
231             return;
232         }
233         // seek forward, consume until p hits index or n (whichever comes first)
234         index = min(index, n);
235         while (p < index) {
236             consume();
237         }
238     }
239 
240     /**
241      * @uml
242      * @override
243      */
244     public override string getText(Interval interval)
245     {
246         int start = interval.a;
247         int stop = interval.b;
248         if (stop >= n)
249             stop = n-1;
250         if (start >= n) return "";
251         //		System.err.println("data: "+Arrays.toString(data)+", n="+n+
252         //						   ", start="+start+
253         //						   ", stop="+stop);
254         return to!string(data[start..stop+1]);
255     }
256 
257     /**
258      * @uml
259      * @override
260      */
261     public override string getSourceName()
262     {
263         if (name is null || name.length == 0) {
264             return IntStreamConstant.UNKNOWN_SOURCE_NAME;
265         }
266         return name;
267     }
268 
269     /**
270      * @uml
271      * @override
272      */
273     public override string toString()
274     {
275         return to!string(data);
276     }
277 
278 }