1 /* 2 * Copyright (c) 2012-2019 The ANTLR Project. All rights reserved. 3 * Use of this file is governed by the BSD 3-clause license that 4 * can be found in the LICENSE.txt file in the project root. 5 */ 6 7 module antlr.v4.runtime.ANTLRInputStream; 8 9 import antlr.v4.runtime.CharStream; 10 import antlr.v4.runtime.IntStream; 11 import antlr.v4.runtime.IntStreamConstant; 12 import antlr.v4.runtime.misc.Interval; 13 import std.algorithm; 14 import std.conv; 15 import std.file; 16 import std.format; 17 import std.stdio; 18 19 /** 20 * Vacuum all input from a {@link Reader}/{@link InputStream} and then treat it 21 * like a {@code char[]} buffer. Can also pass in a {@link String} or 22 * {@code char[]} to use. 23 * 24 * <p>If you need encoding, pass in stream/reader with correct encoding.</p> 25 */ 26 class ANTLRInputStream : CharStream 27 { 28 29 public static int READ_BUFFER_SIZE = 1024; 30 31 public static int INITIAL_BUFFER_SIZE = 1024;; 32 33 /** 34 * The data being scanned 35 */ 36 protected char[] data; 37 38 /** 39 * How many characters are actually in the buffer 40 */ 41 protected int n; 42 43 /** 44 * 0..n-1 index into string of next char 45 */ 46 protected int p = 0; 47 48 /** 49 * What is name or source of this char stream? 50 */ 51 public string name; 52 53 public this() 54 { 55 } 56 57 /** 58 * Copy data in string to a local char array 59 */ 60 public this(string input) 61 { 62 this.data = input.to!(char []); 63 this.n = to!int(input.length); 64 } 65 66 /** 67 * This is the preferred constructor for strings as no data is copied 68 */ 69 public this(char[] data, int numberOfActualCharsInArray) 70 { 71 this.data = data; 72 this.n = numberOfActualCharsInArray; 73 } 74 75 public this(File r) 76 { 77 load(r, INITIAL_BUFFER_SIZE, READ_BUFFER_SIZE); 78 } 79 80 public void load(File r, int size, int readChunkSize) 81 { 82 debug (ANTLRInputStream) 83 writefln("load %1$s in chunks of %2$s", size, readChunkSize); 84 name = r.name; 85 data = to!(char[])(name.readText); 86 // set the actual size of the data available; 87 n = to!int(data.length); 88 debug (ANTLRInputStreamStream) 89 writefln("n= $s", n); 90 } 91 92 /** 93 * Reset the stream so that it's in the same state it was 94 * when the object was created *except* the data array is not 95 * touched. 96 */ 97 public void reset() 98 { 99 p = 0; 100 } 101 102 /** 103 * @uml 104 * @override 105 */ 106 public override void consume() 107 { 108 if (p >= n) { 109 assert (LA(1) == IntStreamConstant.EOF, "cannot consume EOF"); 110 } 111 //System.out.println("prev p="+p+", c="+(char)data[p]); 112 if (p < n) { 113 p++; 114 //System.out.println("p moves to "+p+" (c='"+(char)data[p]+"')"); 115 } 116 } 117 118 /** 119 * @uml 120 * @override 121 */ 122 public override int LA(int i) 123 { 124 if (i == 0) { 125 return 0; // undefined 126 } 127 if (i < 0) { 128 i++; // e.g., translate LA(-1) to use offset i=0; then data[p+0-1] 129 if ((p + i - 1) < 0) { 130 return IntStreamConstant.EOF; // invalid; no char before first char 131 } 132 } 133 if (( p + i - 1) >= n) { 134 debug (ANTLRInputStream) { 135 import std.stdio; 136 writefln("char LA(%s)=EOF; p=%s", i, p); 137 } 138 return IntStreamConstant.EOF; 139 } 140 debug (ANTLRInputStream) { 141 import std.stdio; 142 writefln("LA(%s); p=%s n=%s data.length=%s", i, p, n, data.length); 143 writefln("char LA(%s)=%s; p=%s", i, data[p+i-1], p); 144 } 145 return data[p+i-1]; 146 } 147 148 public int LT(int i) 149 { 150 return LA(i); 151 } 152 153 /** 154 * @uml 155 * @override 156 */ 157 public override int index() 158 { 159 return p; 160 } 161 162 /** 163 * @uml 164 * @override 165 */ 166 public override int size() 167 { 168 return n; 169 } 170 171 /** 172 * mark/release do nothing; we have entire buffer 173 * @uml 174 * @override 175 */ 176 public override int mark() 177 { 178 return -1; 179 } 180 181 /** 182 * @uml 183 * @override 184 */ 185 public override void release(int marker) 186 { 187 } 188 189 /** 190 * consume() ahead until p==index; can't just set p=index as we must 191 * update line and charPositionInLine. If we seek backwards, just set p 192 * @uml 193 * @override 194 */ 195 public override void seek(int index) 196 { 197 if (index <= p) { 198 p = index; // just jump; don't update stream state (line, ...) 199 return; 200 } 201 // seek forward, consume until p hits index or n (whichever comes first) 202 index = min(index, n); 203 while (p < index) { 204 consume(); 205 } 206 } 207 208 /** 209 * @uml 210 * @override 211 */ 212 public override string getText(Interval interval) 213 { 214 int start = interval.a; 215 int stop = interval.b; 216 if (stop >= n) 217 stop = n-1; 218 if (start >= n) return ""; 219 debug (ANTLRInputStream) { 220 writefln("data: %s, n=%s, start=%s, stop=%s", 221 data[start..stop+1], n, start, stop); 222 } 223 return data[start..stop+1].idup(); 224 } 225 226 /** 227 * @uml 228 * @override 229 */ 230 public override string getSourceName() 231 { 232 if (!name) { 233 return IntStreamConstant.UNKNOWN_SOURCE_NAME; 234 } 235 return name; 236 } 237 238 /** 239 * @uml 240 * @override 241 */ 242 public override string toString() 243 { 244 return to!string(data); 245 } 246 247 }