src/jdk/nashorn/internal/parser/AbstractParser.java

Fri, 13 May 2016 18:38:15 +0200

author
hannesw
date
Fri, 13 May 2016 18:38:15 +0200
changeset 1832
133a3c6c906e
parent 1413
fb91ff186894
child 1959
61ffdd1b89f2
permissions
-rw-r--r--

8156714: Parsing issue with automatic semicolon insertion
Reviewed-by: jlaskey, sundar

jlaskey@3 1 /*
jlaskey@7 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
jlaskey@3 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jlaskey@3 4 *
jlaskey@3 5 * This code is free software; you can redistribute it and/or modify it
jlaskey@3 6 * under the terms of the GNU General Public License version 2 only, as
jlaskey@3 7 * published by the Free Software Foundation. Oracle designates this
jlaskey@3 8 * particular file as subject to the "Classpath" exception as provided
jlaskey@3 9 * by Oracle in the LICENSE file that accompanied this code.
jlaskey@3 10 *
jlaskey@3 11 * This code is distributed in the hope that it will be useful, but WITHOUT
jlaskey@3 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jlaskey@3 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
jlaskey@3 14 * version 2 for more details (a copy is included in the LICENSE file that
jlaskey@3 15 * accompanied this code).
jlaskey@3 16 *
jlaskey@3 17 * You should have received a copy of the GNU General Public License version
jlaskey@3 18 * 2 along with this work; if not, write to the Free Software Foundation,
jlaskey@3 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jlaskey@3 20 *
jlaskey@3 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jlaskey@3 22 * or visit www.oracle.com if you need additional information or have any
jlaskey@3 23 * questions.
jlaskey@3 24 */
jlaskey@3 25
jlaskey@3 26 package jdk.nashorn.internal.parser;
jlaskey@3 27
jlaskey@460 28 import static jdk.nashorn.internal.parser.TokenType.COMMENT;
sundar@761 29 import static jdk.nashorn.internal.parser.TokenType.DIRECTIVE_COMMENT;
jlaskey@3 30 import static jdk.nashorn.internal.parser.TokenType.EOF;
jlaskey@3 31 import static jdk.nashorn.internal.parser.TokenType.EOL;
jlaskey@3 32 import static jdk.nashorn.internal.parser.TokenType.IDENT;
attila@975 33 import java.util.HashMap;
attila@975 34 import java.util.Map;
jlaskey@3 35 import jdk.nashorn.internal.ir.IdentNode;
jlaskey@3 36 import jdk.nashorn.internal.ir.LiteralNode;
jlaskey@3 37 import jdk.nashorn.internal.parser.Lexer.LexerToken;
jlaskey@3 38 import jdk.nashorn.internal.parser.Lexer.RegexToken;
jlaskey@3 39 import jdk.nashorn.internal.runtime.ECMAErrors;
jlaskey@3 40 import jdk.nashorn.internal.runtime.ErrorManager;
jlaskey@3 41 import jdk.nashorn.internal.runtime.JSErrorType;
jlaskey@3 42 import jdk.nashorn.internal.runtime.ParserException;
attila@235 43 import jdk.nashorn.internal.runtime.Source;
hannesw@114 44 import jdk.nashorn.internal.runtime.regexp.RegExpFactory;
jlaskey@3 45
jlaskey@3 46 /**
jlaskey@3 47 * Base class for parsers.
jlaskey@3 48 */
jlaskey@3 49 public abstract class AbstractParser {
jlaskey@3 50 /** Source to parse. */
jlaskey@3 51 protected final Source source;
jlaskey@3 52
jlaskey@3 53 /** Error manager to report errors. */
jlaskey@3 54 protected final ErrorManager errors;
jlaskey@3 55
jlaskey@3 56 /** Stream of lex tokens to parse. */
jlaskey@3 57 protected TokenStream stream;
jlaskey@3 58
jlaskey@3 59 /** Index of current token. */
jlaskey@3 60 protected int k;
jlaskey@3 61
attila@963 62 /** Previous token - accessible to sub classes */
attila@963 63 protected long previousToken;
attila@963 64
jlaskey@3 65 /** Descriptor of current token. */
jlaskey@3 66 protected long token;
jlaskey@3 67
jlaskey@3 68 /** Type of current token. */
jlaskey@3 69 protected TokenType type;
jlaskey@3 70
jlaskey@3 71 /** Type of last token. */
jlaskey@3 72 protected TokenType last;
jlaskey@3 73
jlaskey@3 74 /** Start position of current token. */
jlaskey@3 75 protected int start;
jlaskey@3 76
jlaskey@3 77 /** Finish position of previous token. */
jlaskey@3 78 protected int finish;
jlaskey@3 79
jlaskey@3 80 /** Current line number. */
jlaskey@3 81 protected int line;
jlaskey@3 82
jlaskey@3 83 /** Position of last EOL + 1. */
jlaskey@3 84 protected int linePosition;
jlaskey@3 85
jlaskey@3 86 /** Lexer used to scan source content. */
jlaskey@3 87 protected Lexer lexer;
jlaskey@3 88
jlaskey@3 89 /** Is this parser running under strict mode? */
jlaskey@3 90 protected boolean isStrictMode;
jlaskey@3 91
attila@963 92 /** What should line numbers be counted from? */
attila@963 93 protected final int lineOffset;
sundar@761 94
attila@975 95 private final Map<String, String> canonicalNames = new HashMap<>();
attila@975 96
jlaskey@3 97 /**
jlaskey@3 98 * Construct a parser.
jlaskey@3 99 *
attila@963 100 * @param source Source to parse.
attila@963 101 * @param errors Error reporting manager.
attila@963 102 * @param strict True if we are in strict mode
attila@963 103 * @param lineOffset Offset from which lines should be counted
jlaskey@3 104 */
attila@963 105 protected AbstractParser(final Source source, final ErrorManager errors, final boolean strict, final int lineOffset) {
jlaskey@3 106 this.source = source;
jlaskey@3 107 this.errors = errors;
jlaskey@3 108 this.k = -1;
jlaskey@3 109 this.token = Token.toDesc(EOL, 0, 1);
jlaskey@3 110 this.type = EOL;
jlaskey@3 111 this.last = EOL;
jlaskey@3 112 this.isStrictMode = strict;
attila@963 113 this.lineOffset = lineOffset;
jlaskey@3 114 }
jlaskey@3 115
jlaskey@3 116 /**
jlaskey@3 117 * Get the ith token.
jlaskey@3 118 *
jlaskey@3 119 * @param i Index of token.
jlaskey@3 120 *
jlaskey@3 121 * @return the token
jlaskey@3 122 */
jlaskey@3 123 protected final long getToken(final int i) {
jlaskey@3 124 // Make sure there are enough tokens available.
jlaskey@3 125 while (i > stream.last()) {
jlaskey@3 126 // If we need to buffer more for lookahead.
jlaskey@3 127 if (stream.isFull()) {
jlaskey@3 128 stream.grow();
jlaskey@3 129 }
jlaskey@3 130
jlaskey@3 131 // Get more tokens.
jlaskey@3 132 lexer.lexify();
jlaskey@3 133 }
jlaskey@3 134
jlaskey@3 135 return stream.get(i);
jlaskey@3 136 }
jlaskey@3 137
jlaskey@3 138 /**
jlaskey@3 139 * Return the tokenType of the ith token.
jlaskey@3 140 *
jlaskey@3 141 * @param i Index of token
jlaskey@3 142 *
jlaskey@3 143 * @return the token type
jlaskey@3 144 */
jlaskey@3 145 protected final TokenType T(final int i) {
jlaskey@3 146 // Get token descriptor and extract tokenType.
jlaskey@3 147 return Token.descType(getToken(i));
jlaskey@3 148 }
jlaskey@3 149
jlaskey@3 150 /**
jlaskey@460 151 * Seek next token that is not an EOL or comment.
jlaskey@3 152 *
jlaskey@3 153 * @return tokenType of next token.
jlaskey@3 154 */
jlaskey@3 155 protected final TokenType next() {
jlaskey@3 156 do {
jlaskey@3 157 nextOrEOL();
jlaskey@460 158 } while (type == EOL || type == COMMENT);
jlaskey@460 159
jlaskey@460 160 return type;
jlaskey@460 161 }
jlaskey@460 162
jlaskey@460 163 /**
jlaskey@460 164 * Seek next token or EOL (skipping comments.)
jlaskey@460 165 *
jlaskey@460 166 * @return tokenType of next token.
jlaskey@460 167 */
jlaskey@460 168 protected final TokenType nextOrEOL() {
jlaskey@460 169 do {
jlaskey@460 170 nextToken();
sundar@761 171 if (type == DIRECTIVE_COMMENT) {
sundar@761 172 checkDirectiveComment();
sundar@761 173 }
sundar@761 174 } while (type == COMMENT || type == DIRECTIVE_COMMENT);
jlaskey@3 175
jlaskey@3 176 return type;
jlaskey@3 177 }
jlaskey@3 178
sundar@761 179 // sourceURL= after directive comment
sundar@761 180 private static final String SOURCE_URL_PREFIX = "sourceURL=";
sundar@761 181
sundar@761 182 // currently only @sourceURL=foo supported
sundar@761 183 private void checkDirectiveComment() {
sundar@761 184 // if already set, ignore this one
attila@963 185 if (source.getExplicitURL() != null) {
sundar@761 186 return;
sundar@761 187 }
sundar@761 188
sundar@761 189 final String comment = (String) lexer.getValueOf(token, isStrictMode);
sundar@761 190 final int len = comment.length();
sundar@761 191 // 4 characters for directive comment marker //@\s or //#\s
sundar@761 192 if (len > 4 && comment.substring(4).startsWith(SOURCE_URL_PREFIX)) {
attila@963 193 source.setExplicitURL(comment.substring(4 + SOURCE_URL_PREFIX.length()));
sundar@761 194 }
sundar@761 195 }
sundar@761 196
jlaskey@3 197 /**
jlaskey@3 198 * Seek next token.
jlaskey@3 199 *
jlaskey@3 200 * @return tokenType of next token.
jlaskey@3 201 */
sundar@761 202 private TokenType nextToken() {
hannesw@1832 203 // Capture last token type, but ignore comments (which are irrelevant for the purpose of newline detection).
hannesw@1832 204 if (type != COMMENT) {
hannesw@1832 205 last = type;
hannesw@1832 206 }
jlaskey@3 207 if (type != EOF) {
jlaskey@3 208
jlaskey@3 209 // Set up next token.
jlaskey@3 210 k++;
jlaskey@3 211 final long lastToken = token;
attila@963 212 previousToken = token;
jlaskey@3 213 token = getToken(k);
jlaskey@3 214 type = Token.descType(token);
jlaskey@3 215
jlaskey@3 216 // do this before the start is changed below
jlaskey@3 217 if (last != EOL) {
jlaskey@3 218 finish = start + Token.descLength(lastToken);
jlaskey@3 219 }
jlaskey@3 220
jlaskey@3 221 if (type == EOL) {
attila@963 222 line = Token.descLength(token);
jlaskey@3 223 linePosition = Token.descPosition(token);
jlaskey@3 224 } else {
jlaskey@3 225 start = Token.descPosition(token);
jlaskey@3 226 }
jlaskey@3 227
jlaskey@3 228 }
jlaskey@3 229
jlaskey@3 230 return type;
jlaskey@3 231 }
jlaskey@3 232
jlaskey@3 233 /**
jlaskey@3 234 * Get the message string for a message ID and arguments
jlaskey@3 235 *
jlaskey@3 236 * @param msgId The Message ID
jlaskey@3 237 * @param args The arguments
jlaskey@3 238 *
jlaskey@3 239 * @return The message string
jlaskey@3 240 */
jlaskey@3 241 protected static String message(final String msgId, final String... args) {
jlaskey@3 242 return ECMAErrors.getMessage("parser.error." + msgId, args);
jlaskey@3 243 }
jlaskey@3 244
jlaskey@3 245 /**
jlaskey@3 246 * Report an error.
jlaskey@3 247 *
jlaskey@3 248 * @param message Error message.
jlaskey@3 249 * @param errorToken Offending token.
lagergren@211 250 * @return ParserException upon failure. Caller should throw and not ignore
jlaskey@3 251 */
lagergren@211 252 protected final ParserException error(final String message, final long errorToken) {
lagergren@211 253 return error(JSErrorType.SYNTAX_ERROR, message, errorToken);
jlaskey@3 254 }
jlaskey@3 255
jlaskey@3 256 /**
jlaskey@3 257 * Report an error.
jlaskey@3 258 *
jlaskey@3 259 * @param errorType The error type
jlaskey@3 260 * @param message Error message.
jlaskey@3 261 * @param errorToken Offending token.
lagergren@211 262 * @return ParserException upon failure. Caller should throw and not ignore
jlaskey@3 263 */
lagergren@211 264 protected final ParserException error(final JSErrorType errorType, final String message, final long errorToken) {
jlaskey@3 265 final int position = Token.descPosition(errorToken);
jlaskey@3 266 final int lineNum = source.getLine(position);
jlaskey@3 267 final int columnNum = source.getColumn(position);
jlaskey@3 268 final String formatted = ErrorManager.format(message, source, lineNum, columnNum, errorToken);
lagergren@211 269 return new ParserException(errorType, formatted, source, lineNum, columnNum, errorToken);
jlaskey@3 270 }
jlaskey@3 271
jlaskey@3 272 /**
jlaskey@3 273 * Report an error.
jlaskey@3 274 *
jlaskey@3 275 * @param message Error message.
lagergren@211 276 * @return ParserException upon failure. Caller should throw and not ignore
jlaskey@3 277 */
lagergren@211 278 protected final ParserException error(final String message) {
lagergren@211 279 return error(JSErrorType.SYNTAX_ERROR, message);
jlaskey@3 280 }
jlaskey@3 281
jlaskey@3 282 /**
jlaskey@3 283 * Report an error.
jlaskey@3 284 *
jlaskey@3 285 * @param errorType The error type
jlaskey@3 286 * @param message Error message.
lagergren@211 287 * @return ParserException upon failure. Caller should throw and not ignore
jlaskey@3 288 */
lagergren@211 289 protected final ParserException error(final JSErrorType errorType, final String message) {
jlaskey@3 290 // TODO - column needs to account for tabs.
jlaskey@3 291 final int position = Token.descPosition(token);
jlaskey@3 292 final int column = position - linePosition;
jlaskey@3 293 final String formatted = ErrorManager.format(message, source, line, column, token);
lagergren@211 294 return new ParserException(errorType, formatted, source, line, column, token);
jlaskey@3 295 }
jlaskey@3 296
jlaskey@3 297 /**
attila@235 298 * Report a warning to the error manager.
attila@235 299 *
attila@235 300 * @param errorType The error type of the warning
attila@235 301 * @param message Warning message.
lagergren@247 302 * @param errorToken error token
attila@235 303 */
attila@235 304 protected final void warning(final JSErrorType errorType, final String message, final long errorToken) {
attila@235 305 errors.warning(error(errorType, message, errorToken));
attila@235 306 }
attila@235 307
attila@235 308 /**
jlaskey@3 309 * Generate 'expected' message.
jlaskey@3 310 *
jlaskey@3 311 * @param expected Expected tokenType.
jlaskey@3 312 *
jlaskey@3 313 * @return the message string
jlaskey@3 314 */
jlaskey@3 315 protected final String expectMessage(final TokenType expected) {
sundar@97 316 final String tokenString = Token.toString(source, token);
jlaskey@3 317 String msg;
jlaskey@3 318
jlaskey@3 319 if (expected == null) {
jlaskey@3 320 msg = AbstractParser.message("expected.stmt", tokenString);
jlaskey@3 321 } else {
jlaskey@3 322 final String expectedName = expected.getNameOrType();
jlaskey@3 323 msg = AbstractParser.message("expected", expectedName, tokenString);
jlaskey@3 324 }
jlaskey@3 325
jlaskey@3 326 return msg;
jlaskey@3 327 }
jlaskey@3 328
jlaskey@3 329 /**
attila@998 330 * Check current token and advance to the next token.
jlaskey@3 331 *
jlaskey@3 332 * @param expected Expected tokenType.
jlaskey@3 333 *
jlaskey@3 334 * @throws ParserException on unexpected token type
jlaskey@3 335 */
jlaskey@3 336 protected final void expect(final TokenType expected) throws ParserException {
attila@998 337 expectDontAdvance(expected);
attila@998 338 next();
attila@998 339 }
attila@998 340
attila@998 341 /**
attila@998 342 * Check current token, but don't advance to the next token.
attila@998 343 *
attila@998 344 * @param expected Expected tokenType.
attila@998 345 *
attila@998 346 * @throws ParserException on unexpected token type
attila@998 347 */
attila@998 348 protected final void expectDontAdvance(final TokenType expected) throws ParserException {
jlaskey@3 349 if (type != expected) {
lagergren@211 350 throw error(expectMessage(expected));
jlaskey@3 351 }
jlaskey@3 352 }
jlaskey@3 353
jlaskey@3 354 /**
jlaskey@3 355 * Check next token, get its value and advance.
jlaskey@3 356 *
jlaskey@3 357 * @param expected Expected tokenType.
jlaskey@3 358 * @return The JavaScript value of the token
jlaskey@3 359 * @throws ParserException on unexpected token type
jlaskey@3 360 */
jlaskey@3 361 protected final Object expectValue(final TokenType expected) throws ParserException {
jlaskey@3 362 if (type != expected) {
lagergren@211 363 throw error(expectMessage(expected));
jlaskey@3 364 }
jlaskey@3 365
jlaskey@3 366 final Object value = getValue();
jlaskey@3 367
jlaskey@3 368 next();
jlaskey@3 369
jlaskey@3 370 return value;
jlaskey@3 371 }
jlaskey@3 372
jlaskey@3 373 /**
jlaskey@3 374 * Get the value of the current token.
jlaskey@3 375 *
jlaskey@3 376 * @return JavaScript value of the token.
jlaskey@3 377 */
jlaskey@3 378 protected final Object getValue() {
jlaskey@3 379 return getValue(token);
jlaskey@3 380 }
jlaskey@3 381
jlaskey@3 382 /**
jlaskey@3 383 * Get the value of a specific token
jlaskey@3 384 *
jlaskey@3 385 * @param valueToken the token
jlaskey@3 386 *
jlaskey@3 387 * @return JavaScript value of the token
jlaskey@3 388 */
jlaskey@3 389 protected final Object getValue(final long valueToken) {
jlaskey@3 390 try {
jlaskey@3 391 return lexer.getValueOf(valueToken, isStrictMode);
jlaskey@3 392 } catch (final ParserException e) {
jlaskey@3 393 errors.error(e);
jlaskey@3 394 }
jlaskey@3 395
jlaskey@3 396 return null;
jlaskey@3 397 }
jlaskey@3 398
jlaskey@3 399 /**
jlaskey@3 400 * Certain future reserved words can be used as identifiers in
jlaskey@3 401 * non-strict mode. Check if the current token is one such.
jlaskey@3 402 *
jlaskey@3 403 * @return true if non strict mode identifier
jlaskey@3 404 */
jlaskey@3 405 protected final boolean isNonStrictModeIdent() {
jlaskey@3 406 return !isStrictMode && type.getKind() == TokenKind.FUTURESTRICT;
jlaskey@3 407 }
jlaskey@3 408
jlaskey@3 409 /**
jlaskey@3 410 * Get ident.
jlaskey@3 411 *
jlaskey@3 412 * @return Ident node.
jlaskey@3 413 */
jlaskey@3 414 protected final IdentNode getIdent() {
jlaskey@3 415 // Capture IDENT token.
jlaskey@3 416 long identToken = token;
jlaskey@3 417
jlaskey@3 418 if (isNonStrictModeIdent()) {
jlaskey@3 419 // Fake out identifier.
jlaskey@3 420 identToken = Token.recast(token, IDENT);
jlaskey@3 421 // Get IDENT.
jlaskey@3 422 final String ident = (String)getValue(identToken);
jlaskey@3 423
jlaskey@3 424 next();
jlaskey@3 425
jlaskey@3 426 // Create IDENT node.
attila@975 427 return createIdentNode(identToken, finish, ident).setIsFutureStrictName();
jlaskey@3 428 }
jlaskey@3 429
jlaskey@3 430 // Get IDENT.
jlaskey@3 431 final String ident = (String)expectValue(IDENT);
jlaskey@3 432 if (ident == null) {
jlaskey@3 433 return null;
jlaskey@3 434 }
jlaskey@3 435 // Create IDENT node.
attila@975 436 return createIdentNode(identToken, finish, ident);
attila@975 437 }
attila@975 438
attila@975 439 /**
attila@975 440 * Creates a new {@link IdentNode} as if invoked with a {@link IdentNode#IdentNode(long, int, String)
attila@975 441 * constructor} but making sure that the {@code name} is deduplicated within this parse job.
attila@975 442 * @param identToken the token for the new {@code IdentNode}
attila@975 443 * @param identFinish the finish for the new {@code IdentNode}
attila@975 444 * @param name the name for the new {@code IdentNode}. It will be de-duplicated.
attila@975 445 * @return a newly constructed {@code IdentNode} with the specified token, finish, and name; the name will
attila@975 446 * be deduplicated.
attila@975 447 */
attila@975 448 protected IdentNode createIdentNode(final long identToken, final int identFinish, final String name) {
attila@975 449 final String existingName = canonicalNames.putIfAbsent(name, name);
attila@975 450 final String canonicalName = existingName != null ? existingName : name;
attila@975 451 return new IdentNode(identToken, identFinish, canonicalName);
jlaskey@3 452 }
jlaskey@3 453
jlaskey@3 454 /**
jlaskey@3 455 * Check if current token is in identifier name
jlaskey@3 456 *
jlaskey@3 457 * @return true if current token is an identifier name
jlaskey@3 458 */
jlaskey@3 459 protected final boolean isIdentifierName() {
jlaskey@3 460 final TokenKind kind = type.getKind();
jlaskey@3 461 if (kind == TokenKind.KEYWORD || kind == TokenKind.FUTURE || kind == TokenKind.FUTURESTRICT) {
jlaskey@3 462 return true;
jlaskey@3 463 }
sundar@1413 464
sundar@1413 465 // only literals allowed are null, false and true
sundar@1413 466 if (kind == TokenKind.LITERAL) {
sundar@1413 467 switch (type) {
sundar@1413 468 case FALSE:
sundar@1413 469 case NULL:
sundar@1413 470 case TRUE:
sundar@1413 471 return true;
sundar@1413 472 default:
sundar@1413 473 return false;
sundar@1413 474 }
sundar@1413 475 }
sundar@1413 476
jlaskey@3 477 // Fake out identifier.
jlaskey@3 478 final long identToken = Token.recast(token, IDENT);
jlaskey@3 479 // Get IDENT.
jlaskey@3 480 final String ident = (String)getValue(identToken);
jlaskey@3 481 return !ident.isEmpty() && Character.isJavaIdentifierStart(ident.charAt(0));
jlaskey@3 482 }
jlaskey@3 483
jlaskey@3 484 /**
jlaskey@3 485 * Create an IdentNode from the current token
jlaskey@3 486 *
jlaskey@3 487 * @return an IdentNode representing the current token
jlaskey@3 488 */
jlaskey@3 489 protected final IdentNode getIdentifierName() {
jlaskey@3 490 if (type == IDENT) {
jlaskey@3 491 return getIdent();
jlaskey@3 492 } else if (isIdentifierName()) {
jlaskey@3 493 // Fake out identifier.
jlaskey@3 494 final long identToken = Token.recast(token, IDENT);
jlaskey@3 495 // Get IDENT.
jlaskey@3 496 final String ident = (String)getValue(identToken);
jlaskey@3 497 next();
jlaskey@3 498 // Create IDENT node.
attila@975 499 return createIdentNode(identToken, finish, ident);
jlaskey@3 500 } else {
jlaskey@3 501 expect(IDENT);
jlaskey@3 502 return null;
jlaskey@3 503 }
jlaskey@3 504 }
jlaskey@3 505
jlaskey@3 506 /**
jlaskey@3 507 * Create a LiteralNode from the current token
jlaskey@3 508 *
jlaskey@3 509 * @return LiteralNode representing the current token
jlaskey@3 510 * @throws ParserException if any literals fails to parse
jlaskey@3 511 */
jlaskey@3 512 protected final LiteralNode<?> getLiteral() throws ParserException {
jlaskey@3 513 // Capture LITERAL token.
jlaskey@3 514 final long literalToken = token;
jlaskey@3 515
jlaskey@3 516 // Create literal node.
jlaskey@3 517 final Object value = getValue();
jlaskey@9 518 // Advance to have a correct finish
jlaskey@9 519 next();
jlaskey@3 520
jlaskey@3 521 LiteralNode<?> node = null;
jlaskey@3 522
jlaskey@3 523 if (value == null) {
lagergren@252 524 node = LiteralNode.newInstance(literalToken, finish);
jlaskey@3 525 } else if (value instanceof Number) {
lagergren@252 526 node = LiteralNode.newInstance(literalToken, finish, (Number)value);
jlaskey@3 527 } else if (value instanceof String) {
lagergren@252 528 node = LiteralNode.newInstance(literalToken, finish, (String)value);
jlaskey@3 529 } else if (value instanceof LexerToken) {
jlaskey@3 530 if (value instanceof RegexToken) {
jlaskey@3 531 final RegexToken regex = (RegexToken)value;
jlaskey@3 532 try {
hannesw@114 533 RegExpFactory.validate(regex.getExpression(), regex.getOptions());
jlaskey@3 534 } catch (final ParserException e) {
lagergren@211 535 throw error(e.getMessage());
jlaskey@3 536 }
jlaskey@3 537 }
lagergren@252 538 node = LiteralNode.newInstance(literalToken, finish, (LexerToken)value);
jlaskey@3 539 } else {
jlaskey@3 540 assert false : "unknown type for LiteralNode: " + value.getClass();
jlaskey@3 541 }
jlaskey@3 542
jlaskey@3 543 return node;
jlaskey@3 544 }
jlaskey@3 545 }

mercurial