1 /* 2 * Copyright (c) 2012-2018 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.BufferedTokenStream; 8 9 import std.array; 10 import std.format; 11 import std.conv; 12 import std.algorithm: canFind; 13 import antlr.v4.runtime.IllegalStateException; 14 import antlr.v4.runtime.Lexer; 15 import antlr.v4.runtime.RuleContext; 16 import antlr.v4.runtime.Token; 17 import antlr.v4.runtime.TokenConstantDefinition; 18 import antlr.v4.runtime.TokenSource; 19 import antlr.v4.runtime.TokenStream; 20 import antlr.v4.runtime.WritableToken; 21 import antlr.v4.runtime.misc.Interval; 22 23 // Class BufferedTokenStream 24 /** 25 * This implementation of {@link TokenStream} loads tokens from a 26 * {@link TokenSource} on-demand, and places the tokens in a buffer to provide 27 * access to any previous token by index. 28 * 29 * <p> 30 * This token stream ignores the value of {@link Token#getChannel}. If your 31 * parser requires the token stream filter tokens to only those on a particular 32 * channel, such as {@link Token#DEFAULT_CHANNEL} or 33 * {@link Token#HIDDEN_CHANNEL}, use a filtering token stream such a 34 * {@link CommonTokenStream}.</p> 35 */ 36 class BufferedTokenStream : TokenStream 37 { 38 39 /** 40 * The {@link TokenSource} from which tokens for this stream are fetched. 41 */ 42 protected TokenSource tokenSource; 43 44 /** 45 * A collection of all tokens fetched from the token source. The list is 46 * considered a complete view of the input once {@link #fetchedEOF} is set 47 * to {@code true}. 48 */ 49 protected Token[] tokens; 50 51 /** 52 * The index into {@link #tokens} of the current token (next token to 53 * {@link #consume}). {@link #tokens}{@code [}{@link #p}{@code ]} should be 54 * {@link #LT LT(1)}. 55 * 56 * <p>This field is set to -1 when the stream is first constructed or when 57 * {@link #setTokenSource} is called, indicating that the first token has 58 * not yet been fetched from the token source. For additional information, 59 * see the documentation of {@link IntStream} for a description of 60 * Initializing Methods.</p> 61 * @uml 62 * @read 63 */ 64 private int index_ = -1; 65 66 /** 67 * Indicates whether the {@link Token#EOF} token has been fetched from 68 * {@link #tokenSource} and added to {@link #tokens}. This field improves 69 * performance for the following cases: 70 * 71 * <ul> 72 * <li>{@link #consume}: The lookahead check in {@link #consume} to prevent 73 * consuming the EOF symbol is optimized by checking the values of 74 * {@link #fetchedEOF} and {@link #p} instead of calling {@link #LA}.</li> 75 * <li>{@link #fetch}: The check to prevent adding multiple EOF symbols into 76 * {@link #tokens} is trivial with this field.</li> 77 * <ul> 78 */ 79 protected bool fetchedEOF; 80 81 public this(TokenSource tokenSource) 82 in 83 { 84 assert (tokenSource !is null, "tokenSource cannot be null"); 85 } 86 do 87 { 88 this.tokenSource = tokenSource; 89 } 90 91 /** 92 * @uml 93 * @override 94 */ 95 public override TokenSource getTokenSource() 96 { 97 return tokenSource; 98 } 99 100 public int mark() 101 { 102 return 0; 103 } 104 105 public void release(int marker) 106 { 107 // no resources to release 108 } 109 110 public void reset() 111 { 112 seek(0); 113 } 114 115 public void seek(int index) 116 { 117 lazyInit; 118 index_ = adjustSeekIndex(index); 119 } 120 121 public int size() 122 { 123 return to!int(tokens.length); 124 } 125 126 public void consume() 127 { 128 bool skipEofCheck; 129 if (index_ >= 0) { 130 if (fetchedEOF) { 131 // the last token in tokens is EOF. skip check if p indexes any 132 // fetched token except the last. 133 skipEofCheck = index_ < tokens.length - 1; 134 } 135 else { 136 // no EOF token in tokens. skip check if p indexes a fetched token. 137 skipEofCheck = index_ < tokens.length; 138 } 139 } 140 else { 141 // not yet initialized 142 skipEofCheck = false; 143 } 144 145 if (!skipEofCheck && LA(1) == TokenConstantDefinition.EOF) { 146 throw new IllegalStateException("cannot consume EOF"); 147 } 148 149 if (sync(index_ + 1)) { 150 index_ = adjustSeekIndex(index_ + 1); 151 } 152 } 153 154 /** 155 * Make sure index {@code i} in tokens has a token. 156 * 157 * @return {@code true} if a token is located at index {@code i}, otherwise 158 * {@code false}. 159 * @see #get(int i) 160 */ 161 protected bool sync(int i) 162 in 163 { 164 assert (i >= 0); 165 } 166 do 167 { 168 int n = i - to!int(tokens.length) + 1; // how many more elements we need? 169 if ( n > 0 ) { 170 int fetched = fetch(n); 171 return fetched >= n; 172 } 173 return true; 174 } 175 176 /** 177 * Add {@code n} elements to buffer. 178 * 179 * @return The actual number of elements added to the buffer. 180 */ 181 protected int fetch(int n) 182 { 183 if (fetchedEOF) { 184 return 0; 185 } 186 for (int i = 0; i < n; i++) { 187 Token t = tokenSource.nextToken(); 188 if (cast(WritableToken)t) { 189 (cast(WritableToken)t).setTokenIndex(to!int(tokens.length)); 190 } 191 tokens ~= t; 192 if (t.getType == TokenConstantDefinition.EOF) { 193 fetchedEOF = true; 194 return i + 1; 195 } 196 } 197 return n; 198 } 199 200 /** 201 * @uml 202 * @override 203 */ 204 public override Token get(int i) 205 in 206 { 207 assert( i >= 0 && i < tokens.length, format("token index %1$s out of range 0..%2$s", i, tokens.length-1)); 208 } 209 do 210 { 211 return tokens[i]; 212 } 213 214 /** 215 * Get all tokens from start..stop inclusively 216 */ 217 public Token[] get(int start, int stop) 218 { 219 if (start < 0 || stop < 0 ) return null; 220 lazyInit; 221 Token[] subset; 222 if (stop >= tokens.length) stop = to!int(tokens.length) - 1; 223 for (int i = start; i <= stop; i++) { 224 Token t = tokens[i]; 225 if (t.getType == TokenConstantDefinition.EOF) 226 break; 227 subset ~= t; 228 } 229 return subset; 230 } 231 232 public int LA(int i) 233 { 234 return LT(i).getType(); 235 } 236 237 public Token LB(int k) 238 { 239 if ((index_ - k) < 0) 240 return null; 241 return tokens[index_ - k]; 242 } 243 244 /** 245 * @uml 246 * @override 247 */ 248 public override Token LT(int k) 249 { 250 lazyInit(); 251 if (k == 0) 252 return null; 253 if (k < 0) 254 return LB(-k); 255 int i = index_ + k - 1; 256 sync(i); 257 if ( i >= tokens.length ) { // return EOF token 258 // EOF must be last token 259 return tokens[$-1]; 260 } 261 return tokens[i]; 262 } 263 264 /** 265 * Allowed derived classes to modify the behavior of operations which change 266 * the current stream position by adjusting the target token index of a seek 267 * operation. The default implementation simply returns {@code i}. If an 268 * exception is thrown in this method, the current stream index should not be 269 * changed. 270 * 271 * <p>For example, {@link CommonTokenStream} overrides this method to ensure that 272 * the seek target is always an on-channel token.</p> 273 * 274 * @param i The target token index. 275 * @return The adjusted target token index. 276 */ 277 protected int adjustSeekIndex(int i) 278 { 279 return i; 280 } 281 282 protected void lazyInit() 283 { 284 if (index_ == -1) { 285 setup; 286 } 287 } 288 289 protected void setup() 290 { 291 sync(0); 292 index_ = adjustSeekIndex(0); 293 } 294 295 /** 296 * Reset this token stream by setting its token source. 297 */ 298 public void setTokenSource(TokenSource tokenSource) 299 { 300 this.tokenSource = tokenSource; 301 tokens.length = 0; 302 index_ = -1; 303 } 304 305 public Token[] getTokens() 306 { 307 return tokens; 308 } 309 310 public Token[] getTokens(int start, int stop) 311 { 312 return getTokens(start, stop, null); 313 } 314 315 /** 316 * Given a start and stop index, return a List of all tokens in 317 * the token type BitSet. Return null if no tokens were found. This 318 * method looks at both on and off channel tokens. 319 */ 320 public Token[] getTokens(int start, int stop, int[] types) 321 in 322 { 323 lazyInit(); 324 assert(start >= 0 && stop < tokens.length && 325 stop > 0 && start < tokens.length, 326 format("start %1$s or stop %2$s not in 0..%3$s", start, stop, tokens.length - 1)); 327 } 328 do 329 { 330 if (start > stop) 331 return null; 332 333 // list = tokens[start:stop]:{T t, t.getType() in types} 334 Token[] filteredTokens; 335 for (int i=start; i<=stop; i++) { 336 Token t = tokens[i]; 337 if (types is null || types.canFind(t.getType()) ) { 338 filteredTokens ~= t; 339 } 340 } 341 if (filteredTokens.length == 0) { 342 filteredTokens = null; 343 } 344 return filteredTokens; 345 } 346 347 public Token[] getTokens(int start, int stop, int ttype) 348 { 349 int[] s; 350 s ~= ttype; 351 return getTokens(start,stop, s); 352 } 353 354 /** 355 * Given a starting index, return the index of the next token on channel. 356 * Return {@code i} if {@code tokens[i]} is on channel. Return the index of 357 * the EOF token if there are no tokens on channel between {@code i} and 358 * EOF. 359 */ 360 protected int nextTokenOnChannel(int i, int channel) 361 { 362 sync(i); 363 if (i >= size) { 364 return size - 1; 365 } 366 367 Token token = tokens[i]; 368 while (token.getChannel != channel) { 369 if (token.getType == TokenConstantDefinition.EOF) { 370 return i; 371 } 372 373 i++; 374 sync(i); 375 token = tokens[i]; 376 } 377 378 return i; 379 } 380 381 /** 382 * Given a starting index, return the index of the previous token on 383 * channel. Return {@code i} if {@code tokens[i]} is on channel. Return -1 384 * if there are no tokens on channel between {@code i} and 0. 385 * 386 * <p> 387 * If {@code i} specifies an index at or after the EOF token, the EOF token 388 * index is returned. This is due to the fact that the EOF token is treated 389 * as though it were on every channel.</p> 390 */ 391 protected int previousTokenOnChannel(int i, int channel) 392 { 393 sync(i); 394 if (i >= size) { 395 // the EOF token is on every channel 396 return size() - 1; 397 } 398 while (i >= 0) { 399 Token token = tokens[i]; 400 if (token.getType() == TokenConstantDefinition.EOF || token.getChannel == channel) { 401 return i; 402 } 403 i--; 404 } 405 return i; 406 } 407 408 /** 409 * Collect all tokens on specified channel to the right of 410 * the current token up until we see a token on DEFAULT_TOKEN_CHANNEL or 411 * EOF. If channel is -1, find any non default channel token. 412 */ 413 public Token[] getHiddenTokensToRight(int tokenIndex, int channel) 414 in 415 { 416 lazyInit(); 417 assert(tokenIndex >= 0 && tokenIndex < tokens.length, format("%1$s not in 0..%2$s", tokenIndex, tokens.length-1)); 418 } 419 do 420 { 421 int nextOnChannel = 422 nextTokenOnChannel(tokenIndex + 1, Lexer.DEFAULT_TOKEN_CHANNEL); 423 int to; 424 int from = tokenIndex+1; 425 // if none onchannel to right, nextOnChannel=-1 so set to = last token 426 if ( nextOnChannel == -1 ) to = size()-1; 427 else to = nextOnChannel; 428 return filterForChannel(from, to, channel); 429 } 430 431 /** 432 * Collect all hidden tokens (any off-default channel) to the right of 433 * the current token up until we see a token on DEFAULT_TOKEN_CHANNEL 434 * of EOF. 435 */ 436 public Token[] getHiddenTokensToRight(int tokenIndex) 437 { 438 return getHiddenTokensToRight(tokenIndex, -1); 439 } 440 441 /** 442 * Collect all tokens on specified channel to the left of 443 * the current token up until we see a token on DEFAULT_TOKEN_CHANNEL. 444 * If channel is -1, find any non default channel token. 445 */ 446 public Token[] getHiddenTokensToLeft(int tokenIndex, int channel) 447 in 448 { 449 lazyInit(); 450 assert(tokenIndex >= 0 && tokenIndex < tokens.length, format("%1$s not in 0..%2$s", tokenIndex, tokens.length-1)); 451 } 452 do 453 { 454 455 if (tokenIndex == 0) { 456 // obviously no tokens can appear before the first token 457 return null; 458 } 459 int prevOnChannel = 460 previousTokenOnChannel(tokenIndex - 1, Lexer.DEFAULT_TOKEN_CHANNEL); 461 if ( prevOnChannel == tokenIndex - 1 ) return null; 462 // if none onchannel to left, prevOnChannel=-1 then from=0 463 int from = prevOnChannel+1; 464 int to = tokenIndex-1; 465 return filterForChannel(from, to, channel); 466 } 467 468 /** 469 * Collect all hidden tokens (any off-default channel) to the left of 470 * the current token up until we see a token on DEFAULT_TOKEN_CHANNEL. 471 */ 472 public Token[] getHiddenTokensToLeft(int tokenIndex) 473 { 474 return getHiddenTokensToLeft(tokenIndex, -1); 475 } 476 477 /** 478 * Collect all hidden tokens (any off-default channel) to the left of 479 * the current token up until we see a token on DEFAULT_TOKEN_CHANNEL. 480 */ 481 public Token[] filterForChannel(int from, int to, int channel) 482 { 483 Token[] hidden; 484 for (int i=from; i<=to; i++) { 485 Token t = tokens[i]; 486 if (channel == -1) { 487 if (t.getChannel != Lexer.DEFAULT_TOKEN_CHANNEL) hidden ~= t; 488 } 489 else { 490 if (t.getChannel == channel) 491 hidden ~= t; 492 } 493 } 494 if (hidden.length == 0) return null; 495 return hidden; 496 } 497 498 public string getSourceName() 499 { 500 return tokenSource.getSourceName(); 501 } 502 503 /** 504 * @uml 505 * @override 506 */ 507 public override string getText() 508 { 509 lazyInit(); 510 fill(); 511 return getText(Interval.of(0,size()-1)); 512 } 513 514 /** 515 * @uml 516 * @override 517 */ 518 public override string getText(Interval interval) 519 { 520 int start = interval.a; 521 int stop = interval.b; 522 if (start < 0 || stop < 0) return ""; 523 lazyInit(); 524 if (stop >= tokens.length) stop = to!int(tokens.length) - 1; 525 526 auto buf = appender!(string); 527 for (int i = start; i <= stop; i++) { 528 Token t = tokens[i]; 529 if (t.getType == TokenConstantDefinition.EOF) break; 530 buf.put(t.getText()); 531 } 532 return buf.data; 533 } 534 535 /** 536 * @uml 537 * @override 538 */ 539 public override string getText(RuleContext ctx) 540 { 541 return getText(ctx.getSourceInterval()); 542 } 543 544 /** 545 * @uml 546 * @override 547 */ 548 public override string getText(Token start, Token stop) 549 { 550 if (start !is null && stop !is null) { 551 return getText(Interval.of(start.getTokenIndex(), stop.getTokenIndex())); 552 } 553 return ""; 554 } 555 556 /** 557 * Get all tokens from lexer until EOF 558 */ 559 public void fill() 560 { 561 lazyInit(); 562 const int blockSize = 1000; 563 while (true) { 564 int fetched = fetch(blockSize); 565 if (fetched < blockSize) { 566 return; 567 } 568 } 569 } 570 571 public final int index() 572 { 573 return this.index_; 574 } 575 576 }