1 /* |
1 /* |
2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. |
2 * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
5 * This code is free software; you can redistribute it and/or modify it |
6 * under the terms of the GNU General Public License version 2 only, as |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. Oracle designates this |
7 * published by the Free Software Foundation. Oracle designates this |
49 import static jdk.nashorn.internal.parser.TokenType.LPAREN; |
49 import static jdk.nashorn.internal.parser.TokenType.LPAREN; |
50 import static jdk.nashorn.internal.parser.TokenType.RBRACE; |
50 import static jdk.nashorn.internal.parser.TokenType.RBRACE; |
51 import static jdk.nashorn.internal.parser.TokenType.RBRACKET; |
51 import static jdk.nashorn.internal.parser.TokenType.RBRACKET; |
52 import static jdk.nashorn.internal.parser.TokenType.RPAREN; |
52 import static jdk.nashorn.internal.parser.TokenType.RPAREN; |
53 import static jdk.nashorn.internal.parser.TokenType.SEMICOLON; |
53 import static jdk.nashorn.internal.parser.TokenType.SEMICOLON; |
|
54 import static jdk.nashorn.internal.parser.TokenType.TEMPLATE; |
|
55 import static jdk.nashorn.internal.parser.TokenType.TEMPLATE_HEAD; |
|
56 import static jdk.nashorn.internal.parser.TokenType.TEMPLATE_MIDDLE; |
|
57 import static jdk.nashorn.internal.parser.TokenType.TEMPLATE_TAIL; |
54 import static jdk.nashorn.internal.parser.TokenType.TERNARY; |
58 import static jdk.nashorn.internal.parser.TokenType.TERNARY; |
55 import static jdk.nashorn.internal.parser.TokenType.WHILE; |
59 import static jdk.nashorn.internal.parser.TokenType.WHILE; |
56 |
60 |
57 import java.io.Serializable; |
61 import java.io.Serializable; |
58 import java.util.ArrayDeque; |
62 import java.util.ArrayDeque; |
62 import java.util.HashMap; |
66 import java.util.HashMap; |
63 import java.util.HashSet; |
67 import java.util.HashSet; |
64 import java.util.Iterator; |
68 import java.util.Iterator; |
65 import java.util.List; |
69 import java.util.List; |
66 import java.util.Map; |
70 import java.util.Map; |
|
71 |
67 import jdk.internal.dynalink.support.NameCodec; |
72 import jdk.internal.dynalink.support.NameCodec; |
68 import jdk.nashorn.internal.codegen.CompilerConstants; |
73 import jdk.nashorn.internal.codegen.CompilerConstants; |
69 import jdk.nashorn.internal.codegen.Namespace; |
74 import jdk.nashorn.internal.codegen.Namespace; |
70 import jdk.nashorn.internal.ir.AccessNode; |
75 import jdk.nashorn.internal.ir.AccessNode; |
71 import jdk.nashorn.internal.ir.BaseNode; |
76 import jdk.nashorn.internal.ir.BaseNode; |
2385 this.functionNode = function; |
2393 this.functionNode = function; |
2386 } |
2394 } |
2387 } |
2395 } |
2388 |
2396 |
2389 /** |
2397 /** |
|
2398 * Parse left hand side expression. |
|
2399 * |
2390 * LeftHandSideExpression : |
2400 * LeftHandSideExpression : |
2391 * NewExpression |
2401 * NewExpression |
2392 * CallExpression |
2402 * CallExpression |
2393 * |
2403 * |
2394 * CallExpression : |
2404 * CallExpression : |
2395 * MemberExpression Arguments |
2405 * MemberExpression Arguments |
2396 * CallExpression Arguments |
2406 * CallExpression Arguments |
2397 * CallExpression [ Expression ] |
2407 * CallExpression [ Expression ] |
2398 * CallExpression . IdentifierName |
2408 * CallExpression . IdentifierName |
2399 * |
2409 * CallExpression TemplateLiteral |
2400 * See 11.2 |
2410 * |
2401 * |
|
2402 * Parse left hand side expression. |
|
2403 * @return Expression node. |
2411 * @return Expression node. |
2404 */ |
2412 */ |
2405 private Expression leftHandSideExpression() { |
2413 private Expression leftHandSideExpression() { |
2406 int callLine = line; |
2414 int callLine = line; |
2407 long callToken = token; |
2415 long callToken = token; |
2424 // Capture token. |
2432 // Capture token. |
2425 callLine = line; |
2433 callLine = line; |
2426 callToken = token; |
2434 callToken = token; |
2427 |
2435 |
2428 switch (type) { |
2436 switch (type) { |
2429 case LPAREN: |
2437 case LPAREN: { |
2430 // Get NEW or FUNCTION arguments. |
2438 // Get NEW or FUNCTION arguments. |
2431 final List<Expression> arguments = optimizeList(argumentList()); |
2439 final List<Expression> arguments = optimizeList(argumentList()); |
2432 |
2440 |
2433 // Create call node. |
2441 // Create call node. |
2434 lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false); |
2442 lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false); |
2435 |
2443 |
2436 break; |
2444 break; |
2437 |
2445 } |
2438 case LBRACKET: |
2446 case LBRACKET: { |
2439 next(); |
2447 next(); |
2440 |
2448 |
2441 // Get array index. |
2449 // Get array index. |
2442 final Expression rhs = expression(); |
2450 final Expression rhs = expression(); |
2443 |
2451 |
2445 |
2453 |
2446 // Create indexing node. |
2454 // Create indexing node. |
2447 lhs = new IndexNode(callToken, finish, lhs, rhs); |
2455 lhs = new IndexNode(callToken, finish, lhs, rhs); |
2448 |
2456 |
2449 break; |
2457 break; |
2450 |
2458 } |
2451 case PERIOD: |
2459 case PERIOD: { |
2452 next(); |
2460 next(); |
2453 |
2461 |
2454 final IdentNode property = getIdentifierName(); |
2462 final IdentNode property = getIdentifierName(); |
2455 |
2463 |
2456 // Create property access node. |
2464 // Create property access node. |
2457 lhs = new AccessNode(callToken, finish, lhs, property.getName()); |
2465 lhs = new AccessNode(callToken, finish, lhs, property.getName()); |
2458 |
2466 |
2459 break; |
2467 break; |
2460 |
2468 } |
|
2469 case TEMPLATE: |
|
2470 case TEMPLATE_HEAD: { |
|
2471 // tagged template literal |
|
2472 final List<Expression> arguments = templateLiteralArgumentList(); |
|
2473 |
|
2474 lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false); |
|
2475 |
|
2476 break; |
|
2477 } |
2461 default: |
2478 default: |
2462 break loop; |
2479 break loop; |
2463 } |
2480 } |
2464 } |
2481 } |
2465 |
2482 |
2514 |
2531 |
2515 return new UnaryNode(newToken, callNode); |
2532 return new UnaryNode(newToken, callNode); |
2516 } |
2533 } |
2517 |
2534 |
2518 /** |
2535 /** |
|
2536 * Parse member expression. |
|
2537 * |
2519 * MemberExpression : |
2538 * MemberExpression : |
2520 * PrimaryExpression |
2539 * PrimaryExpression |
2521 * FunctionExpression |
2540 * FunctionExpression |
2522 * MemberExpression [ Expression ] |
2541 * MemberExpression [ Expression ] |
2523 * MemberExpression . IdentifierName |
2542 * MemberExpression . IdentifierName |
|
2543 * MemberExpression TemplateLiteral |
2524 * new MemberExpression Arguments |
2544 * new MemberExpression Arguments |
2525 * |
2545 * |
2526 * See 11.2 |
|
2527 * |
|
2528 * Parse member expression. |
|
2529 * @return Expression node. |
2546 * @return Expression node. |
2530 */ |
2547 */ |
2531 private Expression memberExpression() { |
2548 private Expression memberExpression() { |
2532 // Prepare to build operation. |
2549 // Prepare to build operation. |
2533 Expression lhs; |
2550 Expression lhs; |
2577 |
2594 |
2578 final IdentNode property = getIdentifierName(); |
2595 final IdentNode property = getIdentifierName(); |
2579 |
2596 |
2580 // Create property access node. |
2597 // Create property access node. |
2581 lhs = new AccessNode(callToken, finish, lhs, property.getName()); |
2598 lhs = new AccessNode(callToken, finish, lhs, property.getName()); |
|
2599 |
|
2600 break; |
|
2601 } |
|
2602 case TEMPLATE: |
|
2603 case TEMPLATE_HEAD: { |
|
2604 // tagged template literal |
|
2605 final int callLine = line; |
|
2606 final List<Expression> arguments = templateLiteralArgumentList(); |
|
2607 |
|
2608 lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false); |
2582 |
2609 |
2583 break; |
2610 break; |
2584 } |
2611 } |
2585 default: |
2612 default: |
2586 break loop; |
2613 break loop; |
3033 return false; |
3060 return false; |
3034 } |
3061 } |
3035 final ParserState parserState = (ParserState)data.getEndParserState(); |
3062 final ParserState parserState = (ParserState)data.getEndParserState(); |
3036 assert parserState != null; |
3063 assert parserState != null; |
3037 |
3064 |
|
3065 if (k < stream.last() && start < parserState.position && parserState.position <= Token.descPosition(stream.get(stream.last()))) { |
|
3066 // RBRACE is already in the token stream, so fast forward to it |
|
3067 for (; k < stream.last(); k++) { |
|
3068 long nextToken = stream.get(k + 1); |
|
3069 if (Token.descPosition(nextToken) == parserState.position && Token.descType(nextToken) == RBRACE) { |
|
3070 token = stream.get(k); |
|
3071 type = Token.descType(token); |
|
3072 next(); |
|
3073 assert type == RBRACE && start == parserState.position; |
|
3074 return true; |
|
3075 } |
|
3076 } |
|
3077 } |
|
3078 |
3038 stream.reset(); |
3079 stream.reset(); |
3039 lexer = parserState.createLexer(source, lexer, stream, scripting && !env._no_syntax_extensions, env._es6); |
3080 lexer = parserState.createLexer(source, lexer, stream, scripting && !env._no_syntax_extensions, env._es6); |
3040 line = parserState.line; |
3081 line = parserState.line; |
3041 linePosition = parserState.linePosition; |
3082 linePosition = parserState.linePosition; |
3042 // Doesn't really matter, but it's safe to treat it as if there were a semicolon before |
3083 // Doesn't really matter, but it's safe to treat it as if there were a semicolon before |
3423 } |
3464 } |
3424 break; |
3465 break; |
3425 } |
3466 } |
3426 } |
3467 } |
3427 |
3468 |
|
3469 /** |
|
3470 * Parse untagged template literal as string concatenation. |
|
3471 */ |
|
3472 private Expression templateLiteral() { |
|
3473 assert type == TEMPLATE || type == TEMPLATE_HEAD; |
|
3474 final boolean noSubstitutionTemplate = type == TEMPLATE; |
|
3475 long lastLiteralToken = token; |
|
3476 LiteralNode<?> literal = getLiteral(); |
|
3477 if (noSubstitutionTemplate) { |
|
3478 return literal; |
|
3479 } |
|
3480 |
|
3481 Expression concat = literal; |
|
3482 TokenType lastLiteralType; |
|
3483 do { |
|
3484 Expression expression = expression(); |
|
3485 if (type != TEMPLATE_MIDDLE && type != TEMPLATE_TAIL) { |
|
3486 throw error(AbstractParser.message("unterminated.template.expression"), token); |
|
3487 } |
|
3488 concat = new BinaryNode(Token.recast(lastLiteralToken, TokenType.ADD), concat, expression); |
|
3489 lastLiteralType = type; |
|
3490 lastLiteralToken = token; |
|
3491 literal = getLiteral(); |
|
3492 concat = new BinaryNode(Token.recast(lastLiteralToken, TokenType.ADD), concat, literal); |
|
3493 } while (lastLiteralType == TEMPLATE_MIDDLE); |
|
3494 return concat; |
|
3495 } |
|
3496 |
|
3497 /** |
|
3498 * Parse tagged template literal as argument list. |
|
3499 * @return argument list for a tag function call (template object, ...substitutions) |
|
3500 */ |
|
3501 private List<Expression> templateLiteralArgumentList() { |
|
3502 assert type == TEMPLATE || type == TEMPLATE_HEAD; |
|
3503 final ArrayList<Expression> argumentList = new ArrayList<>(); |
|
3504 final ArrayList<Expression> rawStrings = new ArrayList<>(); |
|
3505 final ArrayList<Expression> cookedStrings = new ArrayList<>(); |
|
3506 argumentList.add(null); // filled at the end |
|
3507 |
|
3508 final long templateToken = token; |
|
3509 final boolean hasSubstitutions = type == TEMPLATE_HEAD; |
|
3510 addTemplateLiteralString(rawStrings, cookedStrings); |
|
3511 |
|
3512 if (hasSubstitutions) { |
|
3513 TokenType lastLiteralType; |
|
3514 do { |
|
3515 Expression expression = expression(); |
|
3516 if (type != TEMPLATE_MIDDLE && type != TEMPLATE_TAIL) { |
|
3517 throw error(AbstractParser.message("unterminated.template.expression"), token); |
|
3518 } |
|
3519 argumentList.add(expression); |
|
3520 |
|
3521 lastLiteralType = type; |
|
3522 addTemplateLiteralString(rawStrings, cookedStrings); |
|
3523 } while (lastLiteralType == TEMPLATE_MIDDLE); |
|
3524 } |
|
3525 |
|
3526 final LiteralNode<Expression[]> rawStringArray = LiteralNode.newInstance(templateToken, finish, rawStrings); |
|
3527 final LiteralNode<Expression[]> cookedStringArray = LiteralNode.newInstance(templateToken, finish, cookedStrings); |
|
3528 final RuntimeNode templateObject = new RuntimeNode(templateToken, finish, RuntimeNode.Request.GET_TEMPLATE_OBJECT, rawStringArray, cookedStringArray); |
|
3529 argumentList.set(0, templateObject); |
|
3530 return optimizeList(argumentList); |
|
3531 } |
|
3532 |
|
3533 private void addTemplateLiteralString(final ArrayList<Expression> rawStrings, final ArrayList<Expression> cookedStrings) { |
|
3534 final long stringToken = token; |
|
3535 final String rawString = lexer.valueOfRawString(stringToken); |
|
3536 final String cookedString = (String) getValue(); |
|
3537 next(); |
|
3538 rawStrings.add(LiteralNode.newInstance(stringToken, finish, rawString)); |
|
3539 cookedStrings.add(LiteralNode.newInstance(stringToken, finish, cookedString)); |
|
3540 } |
|
3541 |
3428 @Override |
3542 @Override |
3429 public String toString() { |
3543 public String toString() { |
3430 return "'JavaScript Parsing'"; |
3544 return "'JavaScript Parsing'"; |
3431 } |
3545 } |
3432 |
3546 |