1 31 package org.jruby.lexer.yacc; 32 33 import java.io.IOException ; 34 import java.io.Reader ; 35 36 import org.jruby.util.ByteList; 37 38 48 public class LexerSource { 49 private static final int INITIAL_PUSHBACK_SIZE = 100; 50 private static final int INITIAL_LINEWIDTH_SIZE = 2048; 51 52 private ISourcePositionFactory positionFactory; 54 55 private final Reader reader; 57 58 private char buf[] = new char[INITIAL_PUSHBACK_SIZE]; 60 61 private int bufLength = -1; 63 64 private int lineWidths[] = new int[INITIAL_LINEWIDTH_SIZE]; 67 68 private int lineWidthsLength = -1; 70 71 private final String sourceName; 73 74 private int line = 0; 76 77 private int column = 0; 79 80 private int offset = 0; 82 83 private boolean nextCharIsOnANewLine = true; 85 86 92 public LexerSource(String sourceName, Reader reader) { 93 this.sourceName = sourceName; 94 this.reader = reader; 95 this.positionFactory = new SourcePositionFactory(this); 96 } 97 98 public LexerSource(String sourceName, Reader reader, ISourcePositionFactory factory) { 99 this.sourceName = sourceName; 100 this.reader = reader; 101 this.positionFactory = factory; 102 } 103 104 109 public char read() throws IOException { 110 int length = bufLength; 111 char c; 112 113 if (length >= 0) { 114 c = buf[bufLength--]; 115 } else { 116 c = wrappedRead(); 117 118 if (c == 0) { 120 return c; 122 } 123 } 124 125 if (nextCharIsOnANewLine) { 128 nextCharIsOnANewLine = false; 129 column = 0; 130 } 131 132 offset++; 133 column++; 134 if (c == '\n') { 135 line++; 136 if (length < 0) { 139 lineWidths[++lineWidthsLength] = column; 140 if (lineWidthsLength + 1 == lineWidths.length) { 142 int[] newLineWidths = new int[lineWidths.length + INITIAL_LINEWIDTH_SIZE]; 143 144 System.arraycopy(lineWidths, 0, newLineWidths, 0, lineWidths.length); 145 146 lineWidths = newLineWidths; 147 } 148 } 149 150 nextCharIsOnANewLine = true; 151 } 152 153 return c; 154 } 155 156 162 public void unread(char c) { 163 if (c != (char) 0) { 164 offset--; 165 166 if (c == '\n') { 167 line--; 168 column = lineWidths[line]; 169 nextCharIsOnANewLine = true; 170 } else { 171 column--; 172 } 173 174 buf[++bufLength] = c; 175 if (bufLength + 1 == buf.length) { 178 char[] newBuf = new char[buf.length + INITIAL_PUSHBACK_SIZE]; 179 180 System.arraycopy(buf, 0, newBuf, 0, buf.length); 181 182 buf = newBuf; 183 } 184 } 185 } 186 187 public boolean peek(char to) throws IOException { 188 char c = read(); 189 unread(c); 190 return c == to; 191 } 192 193 197 public String getFilename() { 198 return sourceName; 199 } 200 201 205 public int getLine() { 206 return line; 207 } 208 209 214 public int getColumn() { 215 return column; 216 } 217 218 223 public int getOffset() { 224 return (offset <= 0 ? 0 : offset); 225 } 226 227 232 public ISourcePosition getPosition(ISourcePosition startPosition, boolean inclusive) { 233 return positionFactory.getPosition(startPosition, inclusive); 234 } 235 236 241 public ISourcePosition getPosition() { 242 return positionFactory.getPosition(null, false); 243 } 244 245 public ISourcePositionFactory getPositionFactory() { 246 return positionFactory; 247 } 248 249 255 private char wrappedRead() throws IOException { 256 int c = reader.read(); 257 258 if (c == '\r') { 261 if ((c = reader.read()) != '\n') { 262 unread((char)c); 263 c = '\n'; 264 } else { 265 offset++; 269 column++; 270 } 271 } 272 273 return c != -1 ? (char) c : '\0'; 274 275 } 276 277 284 public static LexerSource getSource(String name, Reader content) { 285 return new LexerSource(name, content); 286 } 287 288 public String readLine() throws IOException { 289 StringBuffer sb = new StringBuffer (80); 290 for (char c = read(); c != '\n' && c != '\0'; c = read()) { 291 sb.append(c); 292 } 293 return sb.toString(); 294 } 295 296 public ByteList readLineBytes() throws IOException { 297 ByteList bytelist = new ByteList(80); 298 299 for (char c = read(); c != '\n' && c != '\0'; c = read()) { 300 bytelist.append(c); 301 } 302 return bytelist; 303 } 304 305 public void unreadMany(CharSequence buffer) { 306 int length = buffer.length(); 307 for (int i = length - 1; i >= 0; i--) { 308 unread(buffer.charAt(i)); 309 } 310 } 311 312 public boolean matchString(String match, boolean indent) throws IOException { 313 int length = match.length(); 314 StringBuffer buffer = new StringBuffer (length + 20); 315 316 if (indent) { 317 char c; 318 while ((c = read()) != '\0') { 319 if (!Character.isWhitespace(c)) { 320 unread(c); 321 break; 322 } 323 buffer.append(c); 324 } 325 } 326 327 for (int i = 0; i < length; i++) { 328 char c = read(); 329 buffer.append(c); 330 if (match.charAt(i) != c) { 331 unreadMany(buffer); 332 return false; 333 } 334 } 335 return true; 336 } 337 338 public boolean wasBeginOfLine() { 339 return getColumn() == 1; 340 } 341 342 public char readEscape() throws IOException { 343 char c = read(); 344 345 switch (c) { 346 case '\\' : return c; 348 case 'n' : return '\n'; 350 case 't' : return '\t'; 352 case 'r' : return '\r'; 354 case 'f' : return '\f'; 356 case 'v' : return '\u0013'; 358 case 'a' : return '\u0007'; 360 case 'e' : return '\u0033'; 362 case '0' : case '1' : case '2' : case '3' : case '4' : case '5' : case '6' : case '7' : 364 unread(c); 365 return scanOct(3); 366 case 'x' : int hexOffset = getColumn(); 368 char hexValue = scanHex(2); 369 370 if (hexOffset == getColumn()) { 372 throw new SyntaxException(getPosition(), "Invalid escape character syntax"); 373 } 374 return hexValue; 375 case 'b' : return '\010'; 377 case 's' : return ' '; 379 case 'M' : 380 if ((c = read()) != '-') { 381 throw new SyntaxException(getPosition(), "Invalid escape character syntax"); 382 } else if ((c = read()) == '\\') { 383 return (char) (readEscape() | 0x80); 384 } else if (c == '\0') { 385 throw new SyntaxException(getPosition(), "Invalid escape character syntax"); 386 } 387 return (char) ((c & 0xff) | 0x80); 388 case 'C' : 389 if ((c = read()) != '-') { 390 throw new SyntaxException(getPosition(), "Invalid escape character syntax"); 391 } 392 case 'c' : 393 if ((c = read()) == '\\') { 394 c = readEscape(); 395 } else if (c == '?') { 396 return '\u0177'; 397 } else if (c == '\0') { 398 throw new SyntaxException(getPosition(), "Invalid escape character syntax"); 399 } 400 return (char) (c & 0x9f); 401 case '\0' : 402 throw new SyntaxException(getPosition(), "Invalid escape character syntax"); 403 default : 404 return c; 405 } 406 } 407 408 private char scanHex(int count) throws IOException { 409 char value = '\0'; 410 411 for (int i = 0; i < count; i++) { 412 char c = read(); 413 414 if (!RubyYaccLexer.isHexChar(c)) { 415 unread(c); 416 break; 417 } 418 419 value <<= 4; 420 value |= Integer.parseInt(""+c, 16) & 15; 421 } 422 423 return value; 424 } 425 426 private char scanOct(int count) throws IOException { 427 char value = '\0'; 428 429 for (int i = 0; i < count; i++) { 430 char c = read(); 431 432 if (!RubyYaccLexer.isOctChar(c)) { 433 unread(c); 434 break; 435 } 436 437 value <<= 3; 438 value |= Integer.parseInt(""+c, 8); 439 } 440 441 return value; 442 } 443 444 450 public char getCharAt(int anOffset) throws IOException { 451 StringBuffer buffer = new StringBuffer (anOffset); 452 453 for (int i = 0; i < anOffset; i++) { 455 buffer.append(read()); 456 } 457 458 int length = buffer.length(); 459 460 if (length == 0){ 462 return '\0'; 463 } 464 465 for (int i = 0; i < length; i++) { 467 unread(buffer.charAt(i)); 468 } 469 470 return buffer.charAt(length - 1); 471 } 472 473 public String toString() { 474 try { 475 StringBuffer buffer = new StringBuffer (20); 476 for (int i = 0; i < 20; i++) { 477 buffer.append(read()); 478 } 479 for (int i = 0; i < 20; i++) { 480 unread(buffer.charAt(buffer.length() - i - 1)); 481 } 482 buffer.append(" ..."); 483 return buffer.toString(); 484 } catch(Exception e) { 485 return null; 486 } 487 } 488 } 489 | Popular Tags |