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 }