52 import static jdk.nashorn.internal.parser.TokenType.SEMICOLON; |
52 import static jdk.nashorn.internal.parser.TokenType.SEMICOLON; |
53 import static jdk.nashorn.internal.parser.TokenType.TERNARY; |
53 import static jdk.nashorn.internal.parser.TokenType.TERNARY; |
54 import static jdk.nashorn.internal.parser.TokenType.WHILE; |
54 import static jdk.nashorn.internal.parser.TokenType.WHILE; |
55 |
55 |
56 import java.util.ArrayList; |
56 import java.util.ArrayList; |
57 import java.util.HashMap; |
|
58 import java.util.HashSet; |
57 import java.util.HashSet; |
59 import java.util.Iterator; |
58 import java.util.Iterator; |
|
59 import java.util.LinkedHashMap; |
60 import java.util.List; |
60 import java.util.List; |
61 import java.util.Map; |
61 import java.util.Map; |
62 import java.util.Stack; |
|
63 import jdk.nashorn.internal.codegen.CompilerConstants; |
62 import jdk.nashorn.internal.codegen.CompilerConstants; |
64 import jdk.nashorn.internal.codegen.Namespace; |
63 import jdk.nashorn.internal.codegen.Namespace; |
65 import jdk.nashorn.internal.ir.AccessNode; |
64 import jdk.nashorn.internal.ir.AccessNode; |
66 import jdk.nashorn.internal.ir.BinaryNode; |
65 import jdk.nashorn.internal.ir.BinaryNode; |
67 import jdk.nashorn.internal.ir.Block; |
66 import jdk.nashorn.internal.ir.Block; |
|
67 import jdk.nashorn.internal.ir.BlockLexicalContext; |
68 import jdk.nashorn.internal.ir.BreakNode; |
68 import jdk.nashorn.internal.ir.BreakNode; |
69 import jdk.nashorn.internal.ir.BreakableNode; |
69 import jdk.nashorn.internal.ir.BreakableNode; |
70 import jdk.nashorn.internal.ir.CallNode; |
70 import jdk.nashorn.internal.ir.CallNode; |
71 import jdk.nashorn.internal.ir.CaseNode; |
71 import jdk.nashorn.internal.ir.CaseNode; |
72 import jdk.nashorn.internal.ir.CatchNode; |
72 import jdk.nashorn.internal.ir.CatchNode; |
73 import jdk.nashorn.internal.ir.ContinueNode; |
73 import jdk.nashorn.internal.ir.ContinueNode; |
74 import jdk.nashorn.internal.ir.DoWhileNode; |
|
75 import jdk.nashorn.internal.ir.EmptyNode; |
74 import jdk.nashorn.internal.ir.EmptyNode; |
76 import jdk.nashorn.internal.ir.ExecuteNode; |
75 import jdk.nashorn.internal.ir.ExecuteNode; |
77 import jdk.nashorn.internal.ir.ForNode; |
76 import jdk.nashorn.internal.ir.ForNode; |
78 import jdk.nashorn.internal.ir.FunctionNode; |
77 import jdk.nashorn.internal.ir.FunctionNode; |
79 import jdk.nashorn.internal.ir.FunctionNode.CompilationState; |
78 import jdk.nashorn.internal.ir.FunctionNode.CompilationState; |
82 import jdk.nashorn.internal.ir.IndexNode; |
81 import jdk.nashorn.internal.ir.IndexNode; |
83 import jdk.nashorn.internal.ir.LabelNode; |
82 import jdk.nashorn.internal.ir.LabelNode; |
84 import jdk.nashorn.internal.ir.LexicalContext; |
83 import jdk.nashorn.internal.ir.LexicalContext; |
85 import jdk.nashorn.internal.ir.LineNumberNode; |
84 import jdk.nashorn.internal.ir.LineNumberNode; |
86 import jdk.nashorn.internal.ir.LiteralNode; |
85 import jdk.nashorn.internal.ir.LiteralNode; |
|
86 import jdk.nashorn.internal.ir.LoopNode; |
87 import jdk.nashorn.internal.ir.Node; |
87 import jdk.nashorn.internal.ir.Node; |
88 import jdk.nashorn.internal.ir.ObjectNode; |
88 import jdk.nashorn.internal.ir.ObjectNode; |
89 import jdk.nashorn.internal.ir.PropertyKey; |
89 import jdk.nashorn.internal.ir.PropertyKey; |
90 import jdk.nashorn.internal.ir.PropertyNode; |
90 import jdk.nashorn.internal.ir.PropertyNode; |
91 import jdk.nashorn.internal.ir.ReturnNode; |
91 import jdk.nashorn.internal.ir.ReturnNode; |
273 * |
274 * |
274 * @return New block. |
275 * @return New block. |
275 */ |
276 */ |
276 private Block newBlock() { |
277 private Block newBlock() { |
277 final Block block = new Block(source, token, Token.descPosition(token)); |
278 final Block block = new Block(source, token, Token.descPosition(token)); |
278 lexicalContext.push(block); |
279 return lc.push(block); |
279 return block; |
|
280 } |
280 } |
281 |
281 |
282 /** |
282 /** |
283 * Set up a new function block. |
283 * Set up a new function block. |
284 * |
284 * |
285 * @param ident Name of function. |
285 * @param ident Name of function. |
286 * @return New block. |
286 * @return New block. |
287 */ |
287 */ |
288 private FunctionNode newFunctionBlock(final IdentNode ident) { |
288 private FunctionNode newFunctionNode(final long startToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind) { |
289 // Build function name. |
289 // Build function name. |
290 final StringBuilder sb = new StringBuilder(); |
290 final StringBuilder sb = new StringBuilder(); |
291 |
291 |
292 final FunctionNode parentFunction = getFunction(); |
292 final FunctionNode parentFunction = lc.getCurrentFunction(); |
293 if(parentFunction != null && !parentFunction.isProgram()) { |
293 if (parentFunction != null && !parentFunction.isProgram()) { |
294 sb.append(parentFunction.getName()).append('$'); |
294 sb.append(parentFunction.getName()).append('$'); |
295 } |
295 } |
296 |
296 |
297 sb.append(ident != null ? ident.getName() : FUNCTION_PREFIX.tag()); |
297 sb.append(ident != null ? ident.getName() : FUNCTION_PREFIX.symbolName()); |
298 final String name = namespace.uniqueName(sb.toString()); |
298 final String name = namespace.uniqueName(sb.toString()); |
299 assert parentFunction != null || name.equals(RUN_SCRIPT.tag()) : "name = " + name;// must not rename runScript(). |
299 assert parentFunction != null || name.equals(RUN_SCRIPT.symbolName()) : "name = " + name;// must not rename runScript(). |
|
300 |
|
301 int flags = 0; |
|
302 if (parentFunction == null) { |
|
303 flags |= FunctionNode.IS_PROGRAM; |
|
304 } |
|
305 if (isStrictMode) { |
|
306 flags |= FunctionNode.IS_STRICT; |
|
307 } |
300 |
308 |
301 // Start new block. |
309 // Start new block. |
302 final FunctionNode functionBlock = new FunctionNode(source, token, Token.descPosition(token), namespace, ident, name); |
310 FunctionNode functionNode = |
303 if(parentFunction == null) { |
311 new FunctionNode( |
304 functionBlock.setProgram(); |
312 source, |
305 } |
313 token, |
306 functionBlock.setStrictMode(isStrictMode); |
314 Token.descPosition(token), |
307 functionBlock.setState(errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED); |
315 startToken, |
308 lexicalContext.push(functionBlock); |
316 namespace, |
309 |
317 ident, |
310 return functionBlock; |
318 name, |
|
319 parameters, |
|
320 kind, |
|
321 flags); |
|
322 |
|
323 functionNode = functionNode.setState(lc, errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED); |
|
324 lc.push(functionNode); |
|
325 // Create new block, and just put it on the context stack, restoreFunctionNode() will associate it with the |
|
326 // FunctionNode. |
|
327 newBlock(); |
|
328 return functionNode; |
311 } |
329 } |
312 |
330 |
313 /** |
331 /** |
314 * Restore the current block. |
332 * Restore the current block. |
315 */ |
333 */ |
316 private void restoreBlock(Block block) { |
334 private Block restoreBlock(final Block block) { |
317 lexicalContext.pop(block); |
335 return lc.pop(block);//.setFlag(lc, flags); |
|
336 } |
|
337 |
|
338 private FunctionNode restoreFunctionNode(final FunctionNode functionNode, final long lastToken) { |
|
339 final Block newBody = restoreBlock(lc.getFunctionBody(functionNode)); |
|
340 |
|
341 return lc.pop(functionNode).setBody(lc, newBody).setLastToken(lc, lastToken); |
318 } |
342 } |
319 |
343 |
320 /** |
344 /** |
321 * Get the statements in a block. |
345 * Get the statements in a block. |
322 * @return Block statements. |
346 * @return Block statements. |
323 */ |
347 */ |
324 private Block getBlock(final boolean needsBraces) { |
348 private Block getBlock(final boolean needsBraces) { |
325 // Set up new block. Captures LBRACE. |
349 // Set up new block. Captures LBRACE. |
326 final Block newBlock = newBlock(); |
350 Block newBlock = newBlock(); |
327 try { |
351 try { |
328 pushControlNode(newBlock); |
|
329 |
|
330 // Block opening brace. |
352 // Block opening brace. |
331 if (needsBraces) { |
353 if (needsBraces) { |
332 expect(LBRACE); |
354 expect(LBRACE); |
333 } |
355 } |
334 |
356 // Accumulate block statements. |
335 try { |
357 statementList(); |
336 // Accumulate block statements. |
358 |
337 statementList(); |
|
338 } finally { |
|
339 popControlNode(); |
|
340 } |
|
341 } finally { |
359 } finally { |
342 restoreBlock(newBlock); |
360 newBlock = restoreBlock(newBlock); |
343 } |
361 } |
344 |
362 |
345 final int possibleEnd = Token.descPosition(token) + Token.descLength(token); |
363 final int possibleEnd = Token.descPosition(token) + Token.descLength(token); |
346 |
364 |
347 // Block closing brace. |
365 // Block closing brace. |
361 private Block getStatement() { |
379 private Block getStatement() { |
362 if (type == LBRACE) { |
380 if (type == LBRACE) { |
363 return getBlock(true); |
381 return getBlock(true); |
364 } |
382 } |
365 // Set up new block. Captures first token. |
383 // Set up new block. Captures first token. |
366 final Block newBlock = newBlock(); |
384 Block newBlock = newBlock(); |
367 |
|
368 try { |
385 try { |
369 // Accumulate statements. |
|
370 statement(); |
386 statement(); |
371 } finally { |
387 } finally { |
372 restoreBlock(newBlock); |
388 newBlock = restoreBlock(newBlock); |
373 } |
389 } |
374 |
|
375 return newBlock; |
390 return newBlock; |
376 } |
391 } |
377 |
392 |
378 /** |
393 /** |
379 * Detect calls to special functions. |
394 * Detect calls to special functions. |
380 * @param ident Called function. |
395 * @param ident Called function. |
381 */ |
396 */ |
382 private void detectSpecialFunction(final IdentNode ident) { |
397 private void detectSpecialFunction(final IdentNode ident) { |
383 final String name = ident.getName(); |
398 final String name = ident.getName(); |
384 |
399 |
385 if (EVAL.tag().equals(name)) { |
400 if (EVAL.symbolName().equals(name)) { |
386 final Iterator<FunctionNode> it = lexicalContext.getFunctions(); |
401 markWithOrEval(lc, FunctionNode.HAS_EVAL); |
387 if(it.hasNext()) { |
|
388 it.next().setHasEval(it); |
|
389 } |
|
390 } |
402 } |
391 } |
403 } |
392 |
404 |
393 /** |
405 /** |
394 * Detect use of special properties. |
406 * Detect use of special properties. |
395 * @param ident Referenced property. |
407 * @param ident Referenced property. |
396 */ |
408 */ |
397 private void detectSpecialProperty(final IdentNode ident) { |
409 private void detectSpecialProperty(final IdentNode ident) { |
398 final String name = ident.getName(); |
410 final String name = ident.getName(); |
399 |
411 |
400 if (ARGUMENTS.tag().equals(name)) { |
412 if (ARGUMENTS.symbolName().equals(name)) { |
401 getFunction().setUsesArguments(); |
413 lc.setFlag(lc.getCurrentFunction(), FunctionNode.USES_ARGUMENTS); |
402 } |
414 } |
403 } |
415 } |
404 |
416 |
405 /** |
417 /** |
406 * Tells whether a IdentNode can be used as L-value of an assignment |
418 * Tells whether a IdentNode can be used as L-value of an assignment |
467 * @param expression Left hand side expression. |
479 * @param expression Left hand side expression. |
468 * @param isPostfix Prefix or postfix. |
480 * @param isPostfix Prefix or postfix. |
469 * @return Reduced expression. |
481 * @return Reduced expression. |
470 */ |
482 */ |
471 private Node incDecExpression(final long firstToken, final TokenType tokenType, final Node expression, final boolean isPostfix) { |
483 private Node incDecExpression(final long firstToken, final TokenType tokenType, final Node expression, final boolean isPostfix) { |
472 long incDecToken = firstToken; |
|
473 if (isPostfix) { |
484 if (isPostfix) { |
474 incDecToken = Token.recast(incDecToken, tokenType == DECPREFIX ? DECPOSTFIX : INCPOSTFIX); |
485 return new UnaryNode(source, Token.recast(firstToken, tokenType == DECPREFIX ? DECPOSTFIX : INCPOSTFIX), expression.getStart(), Token.descPosition(firstToken) + Token.descLength(firstToken), expression); |
475 } |
486 } |
476 |
487 |
477 final UnaryNode node = new UnaryNode(source, incDecToken, expression); |
488 return new UnaryNode(source, firstToken, expression); |
478 if (isPostfix) { |
489 } |
479 node.setStart(expression.getStart()); |
|
480 node.setFinish(Token.descPosition(incDecToken) + Token.descLength(incDecToken)); |
|
481 } |
|
482 |
|
483 return node; |
|
484 } |
|
485 |
|
486 /** |
|
487 * Find a label node in the label stack. |
|
488 * @param ident Ident to find. |
|
489 * @return null or the found label node. |
|
490 */ |
|
491 private LabelNode findLabel(final IdentNode ident) { |
|
492 for (final LabelNode labelNode : getFunction().getLabelStack()) { |
|
493 if (labelNode.getLabel().equals(ident)) { |
|
494 return labelNode; |
|
495 } |
|
496 } |
|
497 |
|
498 return null; |
|
499 } |
|
500 |
|
501 /** |
|
502 * Add a label to the label stack. |
|
503 * @param labelNode Label to add. |
|
504 */ |
|
505 private void pushLabel(final LabelNode labelNode) { |
|
506 getFunction().getLabelStack().push(labelNode); |
|
507 } |
|
508 |
|
509 /** |
|
510 * Remove a label from the label stack. |
|
511 */ |
|
512 private void popLabel() { |
|
513 getFunction().getLabelStack().pop(); |
|
514 } |
|
515 |
|
516 /** |
|
517 * Track the current nesting of controls for break and continue. |
|
518 * @param node For, while, do or switch node. |
|
519 */ |
|
520 private void pushControlNode(final Node node) { |
|
521 final boolean isLoop = node instanceof WhileNode; |
|
522 final boolean isBreakable = node instanceof BreakableNode || node instanceof Block; |
|
523 final FunctionNode function = getFunction(); |
|
524 function.getControlStack().push(node); |
|
525 |
|
526 for (final LabelNode labelNode : function.getLabelStack()) { |
|
527 if (isBreakable && labelNode.getBreakNode() == null) { |
|
528 labelNode.setBreakNode(node); |
|
529 } |
|
530 |
|
531 if (isLoop && labelNode.getContinueNode() == null) { |
|
532 labelNode.setContinueNode(node); |
|
533 } |
|
534 } |
|
535 } |
|
536 |
|
537 /** |
|
538 * Finish with control. |
|
539 */ |
|
540 private void popControlNode() { |
|
541 // Get control stack. |
|
542 final Stack<Node> controlStack = getFunction().getControlStack(); |
|
543 |
|
544 // Can be empty if missing brace. |
|
545 if (!controlStack.isEmpty()) { |
|
546 controlStack.pop(); |
|
547 } |
|
548 } |
|
549 |
|
550 private void popControlNode(final Node node) { |
|
551 // Get control stack. |
|
552 final Stack<Node> controlStack = getFunction().getControlStack(); |
|
553 |
|
554 // Can be empty if missing brace. |
|
555 if (!controlStack.isEmpty() && controlStack.peek() == node) { |
|
556 controlStack.pop(); |
|
557 } |
|
558 } |
|
559 |
|
560 private boolean isInWithBlock() { |
|
561 final Stack<Node> controlStack = getFunction().getControlStack(); |
|
562 for (int i = controlStack.size() - 1; i >= 0; i--) { |
|
563 final Node node = controlStack.get(i); |
|
564 |
|
565 if (node instanceof WithNode) { |
|
566 return true; |
|
567 } |
|
568 } |
|
569 |
|
570 return false; |
|
571 } |
|
572 |
|
573 private <T extends Node> T findControl(final Class<T> ctype) { |
|
574 final Stack<Node> controlStack = getFunction().getControlStack(); |
|
575 for (int i = controlStack.size() - 1; i >= 0; i--) { |
|
576 final Node node = controlStack.get(i); |
|
577 |
|
578 if (ctype.isAssignableFrom(node.getClass())) { |
|
579 return ctype.cast(node); |
|
580 } |
|
581 } |
|
582 |
|
583 return null; |
|
584 } |
|
585 |
|
586 private <T extends Node> List<T> findControls(final Class<T> ctype, final Node to) { |
|
587 final List<T> nodes = new ArrayList<>(); |
|
588 final Stack<Node> controlStack = getFunction().getControlStack(); |
|
589 for (int i = controlStack.size() - 1; i >= 0; i--) { |
|
590 final Node node = controlStack.get(i); |
|
591 |
|
592 if (to == node) { |
|
593 break; //stop looking |
|
594 } |
|
595 |
|
596 if (ctype.isAssignableFrom(node.getClass())) { |
|
597 nodes.add(ctype.cast(node)); |
|
598 } |
|
599 } |
|
600 |
|
601 return nodes; |
|
602 } |
|
603 |
|
604 private <T extends Node> int countControls(final Class<T> ctype, final Node to) { |
|
605 return findControls(ctype, to).size(); |
|
606 } |
|
607 |
|
608 |
490 |
609 /** |
491 /** |
610 * ----------------------------------------------------------------------- |
492 * ----------------------------------------------------------------------- |
611 * |
493 * |
612 * Grammar based on |
494 * Grammar based on |
628 private FunctionNode program(final String scriptName) { |
510 private FunctionNode program(final String scriptName) { |
629 // Make a fake token for the script. |
511 // Make a fake token for the script. |
630 final long functionToken = Token.toDesc(FUNCTION, 0, source.getLength()); |
512 final long functionToken = Token.toDesc(FUNCTION, 0, source.getLength()); |
631 // Set up the script to append elements. |
513 // Set up the script to append elements. |
632 |
514 |
633 final FunctionNode script = newFunctionBlock(new IdentNode(source, functionToken, Token.descPosition(functionToken), scriptName)); |
515 FunctionNode script = newFunctionNode( |
634 |
516 functionToken, |
635 script.setKind(FunctionNode.Kind.SCRIPT); |
517 new IdentNode(source, functionToken, Token.descPosition(functionToken), scriptName), |
636 script.setFirstToken(functionToken); |
518 new ArrayList<IdentNode>(), |
|
519 FunctionNode.Kind.SCRIPT); |
|
520 |
637 functionDeclarations = new ArrayList<>(); |
521 functionDeclarations = new ArrayList<>(); |
638 sourceElements(); |
522 sourceElements(); |
639 script.prependStatements(functionDeclarations); |
523 addFunctionDeclarations(script); |
640 functionDeclarations = null; |
524 functionDeclarations = null; |
|
525 |
641 expect(EOF); |
526 expect(EOF); |
642 script.setLastToken(token); |
527 |
643 script.setFinish(source.getLength() - 1); |
528 script.setFinish(source.getLength() - 1); |
644 |
529 |
|
530 script = restoreFunctionNode(script, token); //commit code |
|
531 script = script.setBody(lc, script.getBody().setNeedsScope(lc)); |
645 return script; |
532 return script; |
646 } |
533 } |
647 |
534 |
648 /** |
535 /** |
649 * Directive value or null if statement is not a directive. |
536 * Directive value or null if statement is not a directive. |
1079 final long ifToken = token; |
944 final long ifToken = token; |
1080 // IF tested in caller. |
945 // IF tested in caller. |
1081 next(); |
946 next(); |
1082 |
947 |
1083 expect(LPAREN); |
948 expect(LPAREN); |
1084 |
|
1085 // Get the test expression. |
|
1086 final Node test = expression(); |
949 final Node test = expression(); |
1087 |
|
1088 expect(RPAREN); |
950 expect(RPAREN); |
1089 |
|
1090 // Get the pass statement. |
|
1091 final Block pass = getStatement(); |
951 final Block pass = getStatement(); |
1092 |
952 |
1093 // Assume no else. |
|
1094 Block fail = null; |
953 Block fail = null; |
1095 |
|
1096 if (type == ELSE) { |
954 if (type == ELSE) { |
1097 next(); |
955 next(); |
1098 |
|
1099 // Get the else block. |
|
1100 fail = getStatement(); |
956 fail = getStatement(); |
1101 } |
957 } |
1102 |
958 |
1103 // Construct and add new if node. |
959 appendStatement(new IfNode(source, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail)); |
1104 final IfNode ifNode = new IfNode(source, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail); |
|
1105 |
|
1106 getBlock().addStatement(ifNode); |
|
1107 } |
960 } |
1108 |
961 |
1109 /** |
962 /** |
1110 * ... IterationStatement: |
963 * ... IterationStatement: |
1111 * ... |
964 * ... |
1118 * |
971 * |
1119 * Parse a FOR statement. |
972 * Parse a FOR statement. |
1120 */ |
973 */ |
1121 private void forStatement() { |
974 private void forStatement() { |
1122 // Create FOR node, capturing FOR token. |
975 // Create FOR node, capturing FOR token. |
1123 final ForNode forNode = new ForNode(source, token, Token.descPosition(token)); |
976 ForNode forNode = new ForNode(source, token, Token.descPosition(token), null, null, null, null, ForNode.IS_FOR); |
1124 |
977 |
1125 pushControlNode(forNode); |
|
1126 |
978 |
1127 // Set up new block for scope of vars. Captures first token. |
979 // Set up new block for scope of vars. Captures first token. |
1128 final Block outer = newBlock(); |
980 Block outer = newBlock(); |
|
981 lc.push(forNode); |
1129 |
982 |
1130 try { |
983 try { |
1131 // FOR tested in caller. |
984 // FOR tested in caller. |
1132 next(); |
985 next(); |
1133 |
986 |
1134 // Nashorn extension: for each expression. |
987 // Nashorn extension: for each expression. |
1135 // iterate property values rather than property names. |
988 // iterate property values rather than property names. |
1136 if (!env._no_syntax_extensions && type == IDENT && "each".equals(getValue())) { |
989 if (!env._no_syntax_extensions && type == IDENT && "each".equals(getValue())) { |
1137 forNode.setIsForEach(); |
990 forNode = forNode.setIsForEach(lc); |
1138 next(); |
991 next(); |
1139 } |
992 } |
1140 |
993 |
1141 expect(LPAREN); |
994 expect(LPAREN); |
1142 |
995 |
1143 /// Capture control information. |
996 List<VarNode> vars = null; |
1144 forControl(forNode); |
997 |
|
998 switch (type) { |
|
999 case VAR: |
|
1000 // Var statements captured in for outer block. |
|
1001 vars = variableStatement(false); |
|
1002 break; |
|
1003 case SEMICOLON: |
|
1004 break; |
|
1005 default: |
|
1006 final Node expression = expression(unaryExpression(), COMMARIGHT.getPrecedence(), true); |
|
1007 forNode = forNode.setInit(lc, expression); |
|
1008 break; |
|
1009 } |
|
1010 |
|
1011 switch (type) { |
|
1012 case SEMICOLON: |
|
1013 // for (init; test; modify) |
|
1014 expect(SEMICOLON); |
|
1015 if (type != SEMICOLON) { |
|
1016 forNode = forNode.setTest(lc, expression()); |
|
1017 } |
|
1018 expect(SEMICOLON); |
|
1019 if (type != RPAREN) { |
|
1020 forNode = forNode.setModify(lc, expression()); |
|
1021 } |
|
1022 break; |
|
1023 |
|
1024 case IN: |
|
1025 forNode = forNode.setIsForIn(lc); |
|
1026 if (vars != null) { |
|
1027 // for (var i in obj) |
|
1028 if (vars.size() == 1) { |
|
1029 forNode = forNode.setInit(lc, new IdentNode(vars.get(0).getName())); |
|
1030 } else { |
|
1031 // for (var i, j in obj) is invalid |
|
1032 throw error(AbstractParser.message("many.vars.in.for.in.loop"), vars.get(1).getToken()); |
|
1033 } |
|
1034 |
|
1035 } else { |
|
1036 // for (expr in obj) |
|
1037 final Node init = forNode.getInit(); |
|
1038 assert init != null : "for..in init expression can not be null here"; |
|
1039 |
|
1040 // check if initial expression is a valid L-value |
|
1041 if (!(init instanceof AccessNode || |
|
1042 init instanceof IndexNode || |
|
1043 init instanceof IdentNode)) { |
|
1044 throw error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken()); |
|
1045 } |
|
1046 |
|
1047 if (init instanceof IdentNode) { |
|
1048 if (!checkIdentLValue((IdentNode)init)) { |
|
1049 throw error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken()); |
|
1050 } |
|
1051 verifyStrictIdent((IdentNode)init, "for-in iterator"); |
|
1052 } |
|
1053 } |
|
1054 |
|
1055 next(); |
|
1056 |
|
1057 // Get the collection expression. |
|
1058 forNode = forNode.setModify(lc, expression()); |
|
1059 break; |
|
1060 |
|
1061 default: |
|
1062 expect(SEMICOLON); |
|
1063 break; |
|
1064 } |
1145 |
1065 |
1146 expect(RPAREN); |
1066 expect(RPAREN); |
1147 |
1067 |
1148 // Set the for body. |
1068 // Set the for body. |
1149 final Block body = getStatement(); |
1069 final Block body = getStatement(); |
1150 forNode.setBody(body); |
1070 forNode = forNode.setBody(lc, body); |
1151 forNode.setFinish(body.getFinish()); |
1071 forNode.setFinish(body.getFinish()); |
1152 outer.setFinish(body.getFinish()); |
1072 outer.setFinish(body.getFinish()); |
1153 |
1073 |
1154 // Add for to current block. |
1074 appendStatement(forNode); |
1155 getBlock().addStatement(forNode); |
|
1156 } finally { |
1075 } finally { |
1157 restoreBlock(outer); |
1076 lc.pop(forNode); |
1158 popControlNode(); |
1077 outer = restoreBlock(outer); |
1159 } |
1078 } |
1160 |
1079 |
1161 getBlock().addStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer)); |
1080 appendStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer)); |
1162 } |
1081 } |
1163 |
1082 |
1164 /** |
1083 /** |
1165 * ... IterationStatement : |
1084 * ... IterationStatement : |
1166 * ... |
1085 * ... |
1173 * |
1092 * |
1174 * Parse the control section of a FOR statement. Also used for |
1093 * Parse the control section of a FOR statement. Also used for |
1175 * comprehensions. |
1094 * comprehensions. |
1176 * @param forNode Owning FOR. |
1095 * @param forNode Owning FOR. |
1177 */ |
1096 */ |
1178 private void forControl(final ForNode forNode) { |
1097 |
1179 List<VarNode> vars = null; |
|
1180 |
|
1181 switch (type) { |
|
1182 case VAR: |
|
1183 // Var statements captured in for outer block. |
|
1184 vars = variableStatement(false); |
|
1185 break; |
|
1186 |
|
1187 case SEMICOLON: |
|
1188 break; |
|
1189 |
|
1190 default: |
|
1191 final Node expression = expression(unaryExpression(), COMMARIGHT.getPrecedence(), true); |
|
1192 forNode.setInit(expression); |
|
1193 } |
|
1194 |
|
1195 switch (type) { |
|
1196 case SEMICOLON: |
|
1197 // for (init; test; modify) |
|
1198 expect(SEMICOLON); |
|
1199 |
|
1200 // Get the test expression. |
|
1201 if (type != SEMICOLON) { |
|
1202 forNode.setTest(expression()); |
|
1203 } |
|
1204 |
|
1205 expect(SEMICOLON); |
|
1206 |
|
1207 // Get the modify expression. |
|
1208 if (type != RPAREN) { |
|
1209 final Node expression = expression(); |
|
1210 forNode.setModify(expression); |
|
1211 } |
|
1212 |
|
1213 break; |
|
1214 |
|
1215 case IN: |
|
1216 forNode.setIsForIn(); |
|
1217 |
|
1218 if (vars != null) { |
|
1219 // for (var i in obj) |
|
1220 if (vars.size() == 1) { |
|
1221 forNode.setInit(new IdentNode(vars.get(0).getName())); |
|
1222 } else { |
|
1223 // for (var i, j in obj) is invalid |
|
1224 error(AbstractParser.message("many.vars.in.for.in.loop"), vars.get(1).getToken()); |
|
1225 } |
|
1226 |
|
1227 } else { |
|
1228 // for (expr in obj) |
|
1229 final Node init = forNode.getInit(); |
|
1230 assert init != null : "for..in init expression can not be null here"; |
|
1231 |
|
1232 // check if initial expression is a valid L-value |
|
1233 if (!(init instanceof AccessNode || |
|
1234 init instanceof IndexNode || |
|
1235 init instanceof IdentNode)) { |
|
1236 error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken()); |
|
1237 } |
|
1238 |
|
1239 if (init instanceof IdentNode) { |
|
1240 if (!checkIdentLValue((IdentNode)init)) { |
|
1241 error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken()); |
|
1242 } |
|
1243 verifyStrictIdent((IdentNode)init, "for-in iterator"); |
|
1244 } |
|
1245 } |
|
1246 |
|
1247 next(); |
|
1248 |
|
1249 // Get the collection expression. |
|
1250 forNode.setModify(expression()); |
|
1251 break; |
|
1252 |
|
1253 default: |
|
1254 expect(SEMICOLON); |
|
1255 break; |
|
1256 } |
|
1257 |
|
1258 } |
|
1259 |
1098 |
1260 /** |
1099 /** |
1261 * ...IterationStatement : |
1100 * ...IterationStatement : |
1262 * ... |
1101 * ... |
1263 * while ( Expression ) Statement |
1102 * while ( Expression ) Statement |
1272 final long whileToken = token; |
1111 final long whileToken = token; |
1273 // WHILE tested in caller. |
1112 // WHILE tested in caller. |
1274 next(); |
1113 next(); |
1275 |
1114 |
1276 // Construct WHILE node. |
1115 // Construct WHILE node. |
1277 final WhileNode whileNode = new WhileNode(source, whileToken, Token.descPosition(whileToken)); |
1116 WhileNode whileNode = new WhileNode(source, whileToken, Token.descPosition(whileToken), false); |
1278 pushControlNode(whileNode); |
1117 lc.push(whileNode); |
1279 |
1118 |
1280 try { |
1119 try { |
1281 expect(LPAREN); |
1120 expect(LPAREN); |
1282 |
1121 whileNode = whileNode.setTest(lc, expression()); |
1283 // Get the test expression. |
|
1284 final Node test = expression(); |
|
1285 whileNode.setTest(test); |
|
1286 |
|
1287 expect(RPAREN); |
1122 expect(RPAREN); |
1288 |
1123 whileNode = whileNode.setBody(lc, getStatement()); |
1289 // Get WHILE body. |
1124 appendStatement(whileNode); |
1290 final Block statements = getStatement(); |
|
1291 whileNode.setBody(statements); |
|
1292 whileNode.setFinish(statements.getFinish()); |
|
1293 |
|
1294 // Add WHILE node. |
|
1295 getBlock().addStatement(whileNode); |
|
1296 } finally { |
1125 } finally { |
1297 popControlNode(); |
1126 lc.pop(whileNode); |
1298 } |
1127 } |
1299 } |
1128 } |
1300 |
1129 |
1301 /** |
1130 /** |
1302 * ...IterationStatement : |
1131 * ...IterationStatement : |
1312 // Capture DO token. |
1141 // Capture DO token. |
1313 final long doToken = token; |
1142 final long doToken = token; |
1314 // DO tested in the caller. |
1143 // DO tested in the caller. |
1315 next(); |
1144 next(); |
1316 |
1145 |
1317 final WhileNode doWhileNode = new DoWhileNode(source, doToken, Token.descPosition(doToken)); |
1146 WhileNode doWhileNode = new WhileNode(source, doToken, Token.descPosition(doToken), true); |
1318 pushControlNode(doWhileNode); |
1147 lc.push(doWhileNode); |
1319 |
1148 |
1320 try { |
1149 try { |
1321 // Get DO body. |
1150 // Get DO body. |
1322 final Block statements = getStatement(); |
1151 doWhileNode = doWhileNode.setBody(lc, getStatement()); |
1323 doWhileNode.setBody(statements); |
|
1324 |
1152 |
1325 expect(WHILE); |
1153 expect(WHILE); |
1326 |
|
1327 expect(LPAREN); |
1154 expect(LPAREN); |
1328 |
1155 doWhileNode = doWhileNode.setTest(lc, expression()); |
1329 // Get the test expression. |
|
1330 final Node test = expression(); |
|
1331 doWhileNode.setTest(test); |
|
1332 |
|
1333 expect(RPAREN); |
1156 expect(RPAREN); |
1334 |
1157 |
1335 if (type == SEMICOLON) { |
1158 if (type == SEMICOLON) { |
1336 endOfLine(); |
1159 endOfLine(); |
1337 } |
1160 } |
1338 |
|
1339 doWhileNode.setFinish(finish); |
1161 doWhileNode.setFinish(finish); |
1340 |
1162 appendStatement(doWhileNode); |
1341 // Add DO node. |
|
1342 getBlock().addStatement(doWhileNode); |
|
1343 } finally { |
1163 } finally { |
1344 popControlNode(); |
1164 lc.pop(doWhileNode); |
1345 } |
1165 } |
1346 } |
1166 } |
1347 |
1167 |
1348 /** |
1168 /** |
1349 * ContinueStatement : |
1169 * ContinueStatement : |
1368 case EOL: |
1188 case EOL: |
1369 break; |
1189 break; |
1370 |
1190 |
1371 default: |
1191 default: |
1372 final IdentNode ident = getIdent(); |
1192 final IdentNode ident = getIdent(); |
1373 labelNode = findLabel(ident); |
1193 labelNode = lc.findLabel(ident.getName()); |
1374 |
1194 |
1375 if (labelNode == null) { |
1195 if (labelNode == null) { |
1376 error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken()); |
1196 throw error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken()); |
1377 } |
1197 } |
1378 |
1198 |
1379 break; |
1199 break; |
1380 } |
1200 } |
1381 |
1201 |
1382 final Node targetNode = labelNode != null ? labelNode.getContinueNode() : findControl(WhileNode.class); |
1202 final IdentNode label = labelNode == null ? null : labelNode.getLabel(); |
|
1203 final LoopNode targetNode = lc.getContinueTo(label); |
1383 |
1204 |
1384 if (targetNode == null) { |
1205 if (targetNode == null) { |
1385 error(AbstractParser.message("illegal.continue.stmt"), continueToken); |
1206 throw error(AbstractParser.message("illegal.continue.stmt"), continueToken); |
1386 } |
1207 } |
1387 |
1208 |
1388 endOfLine(); |
1209 endOfLine(); |
1389 |
1210 |
1390 // Construct and add CONTINUE node. |
1211 // Construct and add CONTINUE node. |
1391 final ContinueNode continueNode = new ContinueNode(source, continueToken, finish, labelNode, targetNode, findControl(TryNode.class)); |
1212 appendStatement(new ContinueNode(source, continueToken, finish, label == null ? null : new IdentNode(label))); |
1392 continueNode.setScopeNestingLevel(countControls(WithNode.class, targetNode)); |
|
1393 |
|
1394 getBlock().addStatement(continueNode); |
|
1395 } |
1213 } |
1396 |
1214 |
1397 /** |
1215 /** |
1398 * BreakStatement : |
1216 * BreakStatement : |
1399 * break Identifier? ; // [no LineTerminator here] |
1217 * break Identifier? ; // [no LineTerminator here] |
1416 case EOL: |
1234 case EOL: |
1417 break; |
1235 break; |
1418 |
1236 |
1419 default: |
1237 default: |
1420 final IdentNode ident = getIdent(); |
1238 final IdentNode ident = getIdent(); |
1421 labelNode = findLabel(ident); |
1239 labelNode = lc.findLabel(ident.getName()); |
1422 |
1240 |
1423 if (labelNode == null) { |
1241 if (labelNode == null) { |
1424 error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken()); |
1242 throw error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken()); |
1425 } |
1243 } |
1426 |
1244 |
1427 break; |
1245 break; |
1428 } |
1246 } |
1429 |
1247 |
1430 final Node targetNode = labelNode != null ? labelNode.getBreakNode() : findControl(BreakableNode.class); |
1248 //either an explicit label - then get its node or just a "break" - get first breakable |
1431 |
1249 //targetNode is what we are breaking out from. |
|
1250 final IdentNode label = labelNode == null ? null : labelNode.getLabel(); |
|
1251 final BreakableNode targetNode = lc.getBreakable(label); |
1432 if (targetNode == null) { |
1252 if (targetNode == null) { |
1433 error(AbstractParser.message("illegal.break.stmt"), breakToken); |
1253 throw error(AbstractParser.message("illegal.break.stmt"), breakToken); |
1434 } |
1254 } |
1435 |
1255 |
1436 endOfLine(); |
1256 endOfLine(); |
1437 |
1257 |
1438 // Construct and add BREAK node. |
1258 // Construct and add BREAK node. |
1439 final BreakNode breakNode = new BreakNode(source, breakToken, finish, labelNode, targetNode, findControl(TryNode.class)); |
1259 appendStatement(new BreakNode(source, breakToken, finish, label == null ? null : new IdentNode(label))); |
1440 breakNode.setScopeNestingLevel(countControls(WithNode.class, targetNode)); |
|
1441 |
|
1442 getBlock().addStatement(breakNode); |
|
1443 } |
1260 } |
1444 |
1261 |
1445 /** |
1262 /** |
1446 * ReturnStatement : |
1263 * ReturnStatement : |
1447 * return Expression? ; // [no LineTerminator here] |
1264 * return Expression? ; // [no LineTerminator here] |
1531 // WITH tested in caller. |
1346 // WITH tested in caller. |
1532 next(); |
1347 next(); |
1533 |
1348 |
1534 // ECMA 12.10.1 strict mode restrictions |
1349 // ECMA 12.10.1 strict mode restrictions |
1535 if (isStrictMode) { |
1350 if (isStrictMode) { |
1536 error(AbstractParser.message("strict.no.with"), withToken); |
1351 throw error(AbstractParser.message("strict.no.with"), withToken); |
1537 } |
1352 } |
1538 |
1353 |
1539 // Get WITH expression. |
1354 // Get WITH expression. |
1540 final WithNode withNode = new WithNode(source, withToken, finish, null, null); |
1355 WithNode withNode = new WithNode(source, withToken, finish); |
1541 final Iterator<FunctionNode> it = lexicalContext.getFunctions(); |
1356 markWithOrEval(lc, FunctionNode.HAS_WITH); |
1542 if(it.hasNext()) { |
|
1543 it.next().setHasWith(it); |
|
1544 } |
|
1545 |
1357 |
1546 try { |
1358 try { |
1547 pushControlNode(withNode); |
1359 lc.push(withNode); |
1548 |
|
1549 expect(LPAREN); |
1360 expect(LPAREN); |
1550 |
1361 withNode = withNode.setExpression(lc, expression()); |
1551 final Node expression = expression(); |
|
1552 withNode.setExpression(expression); |
|
1553 |
|
1554 expect(RPAREN); |
1362 expect(RPAREN); |
1555 |
1363 withNode = withNode.setBody(lc, getStatement()); |
1556 // Get WITH body. |
|
1557 final Block statements = getStatement(); |
|
1558 withNode.setBody(statements); |
|
1559 withNode.setFinish(finish); |
|
1560 } finally { |
1364 } finally { |
1561 popControlNode(withNode); |
1365 lc.pop(withNode); |
1562 } |
1366 } |
1563 |
1367 |
1564 getBlock().addStatement(withNode); |
1368 appendStatement(withNode); |
1565 } |
1369 } |
1566 |
1370 |
1567 /** |
1371 /** |
1568 * SwitchStatement : |
1372 * SwitchStatement : |
1569 * switch ( Expression ) CaseBlock |
1373 * switch ( Expression ) CaseBlock |
1585 * See 12.11 |
1389 * See 12.11 |
1586 * |
1390 * |
1587 * Parse SWITCH statement. |
1391 * Parse SWITCH statement. |
1588 */ |
1392 */ |
1589 private void switchStatement() { |
1393 private void switchStatement() { |
1590 // Capture SWITCH token. |
|
1591 final long switchToken = token; |
1394 final long switchToken = token; |
1592 // SWITCH tested in caller. |
1395 // SWITCH tested in caller. |
1593 next(); |
1396 next(); |
1594 |
1397 |
1595 // Create and add switch statement. |
1398 // Create and add switch statement. |
1596 final SwitchNode switchNode = new SwitchNode(source, switchToken, Token.descPosition(switchToken)); |
1399 SwitchNode switchNode = new SwitchNode(source, switchToken, Token.descPosition(switchToken), null, new ArrayList<CaseNode>(), null); |
1597 pushControlNode(switchNode); |
1400 lc.push(switchNode); |
1598 |
1401 |
1599 try { |
1402 try { |
1600 expect(LPAREN); |
1403 expect(LPAREN); |
1601 |
1404 switchNode = switchNode.setExpression(lc, expression()); |
1602 // Get switch expression. |
|
1603 final Node switchExpression = expression(); |
|
1604 switchNode.setExpression(switchExpression); |
|
1605 |
|
1606 expect(RPAREN); |
1405 expect(RPAREN); |
1607 |
1406 |
1608 expect(LBRACE); |
1407 expect(LBRACE); |
1609 |
1408 |
1610 // Prepare to accumulate cases. |
1409 // Prepare to accumulate cases. |
1681 // Get label ident. |
1472 // Get label ident. |
1682 final IdentNode ident = getIdent(); |
1473 final IdentNode ident = getIdent(); |
1683 |
1474 |
1684 expect(COLON); |
1475 expect(COLON); |
1685 |
1476 |
1686 if (findLabel(ident) != null) { |
1477 if (lc.findLabel(ident.getName()) != null) { |
1687 error(AbstractParser.message("duplicate.label", ident.getName()), labelToken); |
1478 throw error(AbstractParser.message("duplicate.label", ident.getName()), labelToken); |
1688 } |
1479 } |
1689 |
1480 |
|
1481 LabelNode labelNode = new LabelNode(source, labelToken, finish, ident, null); |
1690 try { |
1482 try { |
1691 // Create and add label. |
1483 lc.push(labelNode); |
1692 final LabelNode labelNode = new LabelNode(source, labelToken, finish, ident, null); |
1484 labelNode = labelNode.setBody(lc, getStatement()); |
1693 pushLabel(labelNode); |
|
1694 // Get and save body. |
|
1695 final Block statements = getStatement(); |
|
1696 labelNode.setBody(statements); |
|
1697 labelNode.setFinish(finish); |
1485 labelNode.setFinish(finish); |
1698 |
1486 appendStatement(labelNode); |
1699 getBlock().addStatement(labelNode); |
|
1700 } finally { |
1487 } finally { |
1701 // Remove label. |
1488 assert lc.peek() instanceof LabelNode; |
1702 popLabel(); |
1489 lc.pop(labelNode); |
1703 } |
1490 } |
1704 } |
1491 } |
1705 |
1492 |
1706 /** |
1493 /** |
1707 * ThrowStatement : |
1494 * ThrowStatement : |
1764 final long tryToken = token; |
1549 final long tryToken = token; |
1765 // TRY tested in caller. |
1550 // TRY tested in caller. |
1766 next(); |
1551 next(); |
1767 |
1552 |
1768 // Container block needed to act as target for labeled break statements |
1553 // Container block needed to act as target for labeled break statements |
1769 final Block outer = newBlock(); |
1554 Block outer = newBlock(); |
1770 pushControlNode(outer); |
|
1771 |
1555 |
1772 // Create try. |
1556 // Create try. |
1773 final TryNode tryNode = new TryNode(source, tryToken, Token.descPosition(tryToken), findControl(TryNode.class)); |
|
1774 pushControlNode(tryNode); |
|
1775 |
1557 |
1776 try { |
1558 try { |
1777 // Get TRY body. |
1559 final Block tryBody = getBlock(true); |
1778 final Block tryBody = getBlock(true); |
|
1779 |
|
1780 // Prepare to accumulate catches. |
|
1781 final List<Block> catchBlocks = new ArrayList<>(); |
1560 final List<Block> catchBlocks = new ArrayList<>(); |
1782 |
1561 |
1783 while (type == CATCH) { |
1562 while (type == CATCH) { |
1784 // Capture CATCH token. |
|
1785 final long catchToken = token; |
1563 final long catchToken = token; |
1786 next(); |
1564 next(); |
1787 |
|
1788 expect(LPAREN); |
1565 expect(LPAREN); |
1789 |
|
1790 // Get exception ident. |
|
1791 final IdentNode exception = getIdent(); |
1566 final IdentNode exception = getIdent(); |
1792 |
1567 |
1793 // ECMA 12.4.1 strict mode restrictions |
1568 // ECMA 12.4.1 strict mode restrictions |
1794 verifyStrictIdent(exception, "catch argument"); |
1569 verifyStrictIdent(exception, "catch argument"); |
1795 |
1570 |
1796 // Check for conditional catch. |
1571 // Check for conditional catch. |
1797 Node ifExpression = null; |
1572 Node ifExpression = null; |
1798 |
|
1799 if (type == IF) { |
1573 if (type == IF) { |
1800 next(); |
1574 next(); |
1801 |
|
1802 // Get the exception condition. |
1575 // Get the exception condition. |
1803 ifExpression = expression(); |
1576 ifExpression = expression(); |
1804 } |
1577 } |
1805 |
1578 |
1806 expect(RPAREN); |
1579 expect(RPAREN); |
1807 |
1580 |
1808 final Block catchBlock = newBlock(); |
1581 Block catchBlock = newBlock(); |
1809 try { |
1582 try { |
1810 |
|
1811 // Get CATCH body. |
1583 // Get CATCH body. |
1812 final Block catchBody = getBlock(true); |
1584 final Block catchBody = getBlock(true); |
1813 |
|
1814 // Create and add catch. |
|
1815 final CatchNode catchNode = new CatchNode(source, catchToken, finish, exception, ifExpression, catchBody); |
1585 final CatchNode catchNode = new CatchNode(source, catchToken, finish, exception, ifExpression, catchBody); |
1816 getBlock().addStatement(catchNode); |
1586 appendStatement(catchNode); |
|
1587 } finally { |
|
1588 catchBlock = restoreBlock(catchBlock); |
1817 catchBlocks.add(catchBlock); |
1589 catchBlocks.add(catchBlock); |
1818 } finally { |
|
1819 restoreBlock(catchBlock); |
|
1820 } |
1590 } |
1821 |
1591 |
1822 // If unconditional catch then should to be the end. |
1592 // If unconditional catch then should to be the end. |
1823 if (ifExpression == null) { |
1593 if (ifExpression == null) { |
1824 break; |
1594 break; |
1825 } |
1595 } |
1826 } |
1596 } |
1827 |
1597 |
1828 popControlNode(); |
|
1829 |
|
1830 // Prepare to capture finally statement. |
1598 // Prepare to capture finally statement. |
1831 Block finallyStatements = null; |
1599 Block finallyStatements = null; |
1832 |
1600 |
1833 if (type == FINALLY) { |
1601 if (type == FINALLY) { |
1834 next(); |
1602 next(); |
1835 |
|
1836 // Get FINALLY body. |
|
1837 finallyStatements = getBlock(true); |
1603 finallyStatements = getBlock(true); |
1838 } |
1604 } |
1839 |
1605 |
1840 // Need at least one catch or a finally. |
1606 // Need at least one catch or a finally. |
1841 if (catchBlocks.isEmpty() && finallyStatements == null) { |
1607 if (catchBlocks.isEmpty() && finallyStatements == null) { |
1842 error(AbstractParser.message("missing.catch.or.finally"), tryToken); |
1608 throw error(AbstractParser.message("missing.catch.or.finally"), tryToken); |
1843 } |
1609 } |
1844 |
1610 |
1845 tryNode.setBody(tryBody); |
1611 final TryNode tryNode = new TryNode(source, tryToken, Token.descPosition(tryToken), tryBody, catchBlocks, finallyStatements); |
1846 tryNode.setCatchBlocks(catchBlocks); |
1612 // Add try. |
1847 tryNode.setFinallyBody(finallyStatements); |
1613 assert lc.peek() == outer; |
|
1614 appendStatement(tryNode); |
|
1615 |
1848 tryNode.setFinish(finish); |
1616 tryNode.setFinish(finish); |
1849 outer.setFinish(finish); |
1617 outer.setFinish(finish); |
1850 |
1618 |
1851 // Add try. |
|
1852 outer.addStatement(tryNode); |
|
1853 } finally { |
1619 } finally { |
1854 popControlNode(tryNode); |
1620 outer = restoreBlock(outer); |
1855 restoreBlock(outer); |
1621 } |
1856 popControlNode(outer); |
1622 |
1857 } |
1623 appendStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer)); |
1858 |
|
1859 getBlock().addStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer)); |
|
1860 } |
1624 } |
1861 |
1625 |
1862 /** |
1626 /** |
1863 * DebuggerStatement : |
1627 * DebuggerStatement : |
1864 * debugger ; |
1628 * debugger ; |
2094 commaSeen = true; |
1855 commaSeen = true; |
2095 break; |
1856 break; |
2096 |
1857 |
2097 default: |
1858 default: |
2098 if (!commaSeen) { |
1859 if (!commaSeen) { |
2099 error(AbstractParser.message("expected.comma", type.getNameOrType())); |
1860 throw error(AbstractParser.message("expected.comma", type.getNameOrType())); |
2100 } |
1861 } |
2101 |
1862 |
2102 commaSeen = false; |
1863 commaSeen = false; |
2103 // Get and add the next property. |
1864 // Get and add the next property. |
2104 final PropertyNode property = propertyAssignment(); |
1865 final PropertyNode property = propertyAssignment(); |
2105 final Object key = property.getKeyName(); |
1866 final String key = property.getKeyName(); |
2106 final PropertyNode existingProperty = map.get(key); |
1867 final PropertyNode existingProperty = map.get(key); |
2107 |
1868 |
2108 if (existingProperty != null) { |
1869 if (existingProperty == null) { |
|
1870 map.put(key, property); |
|
1871 // elements.add(property); |
|
1872 break; |
|
1873 } |
|
1874 |
2109 // ECMA section 11.1.5 Object Initialiser |
1875 // ECMA section 11.1.5 Object Initialiser |
2110 // point # 4 on property assignment production |
1876 // point # 4 on property assignment production |
2111 final Node value = property.getValue(); |
1877 final Node value = property.getValue(); |
2112 final Node getter = property.getGetter(); |
1878 final FunctionNode getter = property.getGetter(); |
2113 final Node setter = property.getSetter(); |
1879 final FunctionNode setter = property.getSetter(); |
2114 |
1880 |
2115 final Node prevValue = existingProperty.getValue(); |
1881 final Node prevValue = existingProperty.getValue(); |
2116 final Node prevGetter = existingProperty.getGetter(); |
1882 final FunctionNode prevGetter = existingProperty.getGetter(); |
2117 final Node prevSetter = existingProperty.getSetter(); |
1883 final FunctionNode prevSetter = existingProperty.getSetter(); |
2118 |
1884 |
2119 boolean redefinitionOk = true; |
1885 boolean redefinitionOk = true; |
2120 // ECMA 11.1.5 strict mode restrictions |
1886 // ECMA 11.1.5 strict mode restrictions |
2121 if (isStrictMode) { |
1887 if (isStrictMode) { |
2122 if (value != null && prevValue != null) { |
1888 if (value != null && prevValue != null) { |
2123 redefinitionOk = false; |
1889 redefinitionOk = false; |
2124 } |
1890 } |
2125 } |
1891 } |
2126 |
1892 |
2127 final boolean isPrevAccessor = prevGetter != null || prevSetter != null; |
1893 final boolean isPrevAccessor = prevGetter != null || prevSetter != null; |
2128 final boolean isAccessor = getter != null || setter != null; |
1894 final boolean isAccessor = getter != null || setter != null; |
2129 |
1895 |
2130 // data property redefined as accessor property |
1896 // data property redefined as accessor property |
2131 if (prevValue != null && isAccessor) { |
1897 if (prevValue != null && isAccessor) { |
2132 redefinitionOk = false; |
1898 redefinitionOk = false; |
2133 } |
1899 } |
2143 redefinitionOk = false; |
1909 redefinitionOk = false; |
2144 } |
1910 } |
2145 } |
1911 } |
2146 |
1912 |
2147 if (!redefinitionOk) { |
1913 if (!redefinitionOk) { |
2148 error(AbstractParser.message("property.redefinition", key.toString()), property.getToken()); |
1914 throw error(AbstractParser.message("property.redefinition", key.toString()), property.getToken()); |
2149 } |
1915 } |
2150 |
1916 |
|
1917 PropertyNode newProperty = existingProperty; |
2151 if (value != null) { |
1918 if (value != null) { |
2152 final Node existingValue = existingProperty.getValue(); |
1919 if (prevValue == null) { |
2153 |
1920 map.put(key, newProperty = newProperty.setValue(value)); |
2154 if (existingValue == null) { |
|
2155 existingProperty.setValue(value); |
|
2156 } else { |
1921 } else { |
2157 final long propertyToken = Token.recast(existingProperty.getToken(), COMMARIGHT); |
1922 final long propertyToken = Token.recast(newProperty.getToken(), COMMARIGHT); |
2158 existingProperty.setValue(new BinaryNode(source, propertyToken, existingValue, value)); |
1923 map.put(key, newProperty = newProperty.setValue(new BinaryNode(source, propertyToken, prevValue, value))); |
2159 } |
1924 } |
2160 |
1925 |
2161 existingProperty.setGetter(null); |
1926 map.put(key, newProperty = newProperty.setGetter(null).setSetter(null)); |
2162 existingProperty.setSetter(null); |
|
2163 } |
1927 } |
2164 |
1928 |
2165 if (getter != null) { |
1929 if (getter != null) { |
2166 existingProperty.setGetter(getter); |
1930 map.put(key, newProperty = newProperty.setGetter(getter)); |
2167 } |
1931 } |
2168 |
1932 |
2169 if (setter != null) { |
1933 if (setter != null) { |
2170 existingProperty.setSetter(setter); |
1934 map.put(key, newProperty = newProperty.setSetter(setter)); |
2171 } |
1935 } |
2172 } else { |
1936 break; |
2173 map.put(key, property); |
1937 } |
2174 elements.add(property); |
1938 } |
2175 } |
1939 |
2176 |
1940 return new ObjectNode(source, objectToken, finish, new ArrayList<Node>(map.values())); |
2177 break; |
|
2178 } |
|
2179 } |
|
2180 |
|
2181 return new ObjectNode(source, objectToken, finish, elements); |
|
2182 } |
1941 } |
2183 |
1942 |
2184 /** |
1943 /** |
2185 * PropertyName : |
1944 * PropertyName : |
2186 * IdentifierName |
1945 * IdentifierName |
2251 final PropertyKey getIdent = propertyName(); |
2008 final PropertyKey getIdent = propertyName(); |
2252 final String getterName = getIdent.getPropertyName(); |
2009 final String getterName = getIdent.getPropertyName(); |
2253 final IdentNode getNameNode = new IdentNode(source, ((Node)getIdent).getToken(), finish, "get " + getterName); |
2010 final IdentNode getNameNode = new IdentNode(source, ((Node)getIdent).getToken(), finish, "get " + getterName); |
2254 expect(LPAREN); |
2011 expect(LPAREN); |
2255 expect(RPAREN); |
2012 expect(RPAREN); |
2256 parameters = new ArrayList<>(); |
2013 functionNode = functionBody(getSetToken, getNameNode, new ArrayList<IdentNode>(), FunctionNode.Kind.GETTER); |
2257 functionNode = functionBody(getSetToken, getNameNode, parameters, FunctionNode.Kind.GETTER); |
2014 return new PropertyNode(source, propertyToken, finish, getIdent, null, functionNode, null); |
2258 propertyNode = new PropertyNode(source, propertyToken, finish, getIdent, null); |
|
2259 propertyNode.setGetter(functionNode); |
|
2260 return propertyNode; |
|
2261 |
2015 |
2262 case "set": |
2016 case "set": |
2263 final PropertyKey setIdent = propertyName(); |
2017 final PropertyKey setIdent = propertyName(); |
2264 final String setterName = setIdent.getPropertyName(); |
2018 final String setterName = setIdent.getPropertyName(); |
2265 final IdentNode setNameNode = new IdentNode(source, ((Node)setIdent).getToken(), finish, "set " + setterName); |
2019 final IdentNode setNameNode = new IdentNode(source, ((Node)setIdent).getToken(), finish, "set " + setterName); |
2266 expect(LPAREN); |
2020 expect(LPAREN); |
2267 final IdentNode argIdent = getIdent(); |
2021 final IdentNode argIdent = getIdent(); |
2268 verifyStrictIdent(argIdent, "setter argument"); |
2022 verifyStrictIdent(argIdent, "setter argument"); |
2269 expect(RPAREN); |
2023 expect(RPAREN); |
2270 parameters = new ArrayList<>(); |
2024 List<IdentNode> parameters = new ArrayList<>(); |
2271 parameters.add(argIdent); |
2025 parameters.add(argIdent); |
2272 functionNode = functionBody(getSetToken, setNameNode, parameters, FunctionNode.Kind.SETTER); |
2026 functionNode = functionBody(getSetToken, setNameNode, parameters, FunctionNode.Kind.SETTER); |
2273 propertyNode = new PropertyNode(source, propertyToken, finish, setIdent, null); |
2027 return new PropertyNode(source, propertyToken, finish, setIdent, null, null, functionNode); |
2274 propertyNode.setSetter(functionNode); |
|
2275 return propertyNode; |
|
2276 |
2028 |
2277 default: |
2029 default: |
2278 break; |
2030 break; |
2279 } |
2031 } |
2280 } |
2032 } |
2583 name = new IdentNode(source, functionToken, Token.descPosition(functionToken), tmpName); |
2327 name = new IdentNode(source, functionToken, Token.descPosition(functionToken), tmpName); |
2584 isAnonymous = true; |
2328 isAnonymous = true; |
2585 } |
2329 } |
2586 |
2330 |
2587 expect(LPAREN); |
2331 expect(LPAREN); |
2588 |
|
2589 final List<IdentNode> parameters = formalParameterList(); |
2332 final List<IdentNode> parameters = formalParameterList(); |
2590 |
|
2591 expect(RPAREN); |
2333 expect(RPAREN); |
2592 |
2334 |
2593 final FunctionNode functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL); |
2335 FunctionNode functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL); |
2594 |
2336 |
2595 if (isStatement) { |
2337 if (isStatement) { |
2596 if(topLevel) { |
2338 if (topLevel) { |
2597 functionNode.setIsDeclared(); |
2339 functionNode = functionNode.setFlag(lc, FunctionNode.IS_DECLARED); |
2598 } |
2340 } |
2599 if(ARGUMENTS.tag().equals(name.getName())) { |
2341 if (ARGUMENTS.symbolName().equals(name.getName())) { |
2600 getFunction().setDefinesArguments(); |
2342 functionNode = functionNode.setFlag(lc, FunctionNode.DEFINES_ARGUMENTS); |
2601 } |
2343 } |
2602 } |
2344 } |
2603 |
2345 |
2604 if (isAnonymous) { |
2346 if (isAnonymous) { |
2605 functionNode.setIsAnonymous(); |
2347 functionNode = functionNode.setFlag(lc, FunctionNode.IS_ANONYMOUS); |
2606 } |
2348 } |
2607 |
2349 |
2608 final int arity = parameters.size(); |
2350 final int arity = parameters.size(); |
2609 |
2351 |
2610 final boolean strict = functionNode.isStrictMode(); |
2352 final boolean strict = functionNode.isStrict(); |
2611 if (arity > 1) { |
2353 if (arity > 1) { |
2612 final HashSet<String> parametersSet = new HashSet<>(arity); |
2354 final HashSet<String> parametersSet = new HashSet<>(arity); |
2613 |
2355 |
2614 for (int i = arity - 1; i >= 0; i--) { |
2356 for (int i = arity - 1; i >= 0; i--) { |
2615 final IdentNode parameter = parameters.get(i); |
2357 final IdentNode parameter = parameters.get(i); |
2616 String parameterName = parameter.getName(); |
2358 String parameterName = parameter.getName(); |
2617 |
2359 |
2618 if (ARGUMENTS.tag().equals(parameterName)) { |
2360 if (ARGUMENTS.symbolName().equals(parameterName)) { |
2619 functionNode.setDefinesArguments(); |
2361 functionNode = functionNode.setFlag(lc, FunctionNode.DEFINES_ARGUMENTS); |
2620 } |
2362 } |
2621 |
2363 |
2622 if (parametersSet.contains(parameterName)) { |
2364 if (parametersSet.contains(parameterName)) { |
2623 // redefinition of parameter name |
2365 // redefinition of parameter name |
2624 if (strict) { |
2366 if (strict) { |
2625 error(AbstractParser.message("strict.param.redefinition", parameterName), parameter.getToken()); |
2367 throw error(AbstractParser.message("strict.param.redefinition", parameterName), parameter.getToken()); |
2626 } else { |
|
2627 // rename in non-strict mode |
|
2628 parameterName = functionNode.uniqueName(parameterName); |
|
2629 final long parameterToken = parameter.getToken(); |
|
2630 parameters.set(i, new IdentNode(source, parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName))); |
|
2631 } |
2368 } |
|
2369 // rename in non-strict mode |
|
2370 parameterName = functionNode.uniqueName(parameterName); |
|
2371 final long parameterToken = parameter.getToken(); |
|
2372 parameters.set(i, new IdentNode(source, parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName))); |
2632 } |
2373 } |
2633 |
2374 |
2634 parametersSet.add(parameterName); |
2375 parametersSet.add(parameterName); |
2635 } |
2376 } |
2636 } else if (arity == 1) { |
2377 } else if (arity == 1) { |
2637 if (ARGUMENTS.tag().equals(parameters.get(0).getName())) { |
2378 if (ARGUMENTS.symbolName().equals(parameters.get(0).getName())) { |
2638 functionNode.setDefinesArguments(); |
2379 functionNode = functionNode.setFlag(lc, FunctionNode.DEFINES_ARGUMENTS); |
2639 } |
2380 } |
2640 } |
2381 } |
2641 |
2382 |
2642 if (isStatement) { |
2383 if (isStatement) { |
2643 final VarNode varNode = new VarNode(source, functionToken, finish, name, functionNode, true); |
2384 final VarNode varNode = new VarNode(source, functionToken, finish, name, functionNode, VarNode.IS_STATEMENT); |
2644 if(topLevel) { |
2385 if (topLevel) { |
2645 functionDeclarations.add(lineNumber); |
2386 functionDeclarations.add(lineNumber); |
2646 functionDeclarations.add(varNode); |
2387 functionDeclarations.add(varNode); |
2647 } else { |
2388 } else { |
2648 final Block block = getBlock(); |
2389 appendStatement(lineNumber); |
2649 block.addStatement(lineNumber); |
2390 appendStatement(varNode); |
2650 block.addStatement(varNode); |
|
2651 } |
2391 } |
2652 } |
2392 } |
2653 |
2393 |
2654 return functionNode; |
2394 return functionNode; |
2655 } |
2395 } |
2699 * Parse function body. |
2439 * Parse function body. |
2700 * @return function node (body.) |
2440 * @return function node (body.) |
2701 */ |
2441 */ |
2702 private FunctionNode functionBody(final long firstToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind) { |
2442 private FunctionNode functionBody(final long firstToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind) { |
2703 FunctionNode functionNode = null; |
2443 FunctionNode functionNode = null; |
|
2444 long lastToken = 0L; |
2704 |
2445 |
2705 try { |
2446 try { |
2706 // Create a new function block. |
2447 // Create a new function block. |
2707 functionNode = newFunctionBlock(ident); |
2448 functionNode = newFunctionNode(firstToken, ident, parameters, kind); |
2708 functionNode.setParameters(parameters); |
|
2709 functionNode.setKind(kind); |
|
2710 functionNode.setFirstToken(firstToken); |
|
2711 |
2449 |
2712 // Nashorn extension: expression closures |
2450 // Nashorn extension: expression closures |
2713 if (!env._no_syntax_extensions && type != LBRACE) { |
2451 if (!env._no_syntax_extensions && type != LBRACE) { |
2714 /* |
2452 /* |
2715 * Example: |
2453 * Example: |
2718 * print(square(3)); |
2456 * print(square(3)); |
2719 */ |
2457 */ |
2720 |
2458 |
2721 // just expression as function body |
2459 // just expression as function body |
2722 final Node expr = expression(); |
2460 final Node expr = expression(); |
2723 |
2461 assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode); |
2724 // create a return statement - this creates code in itself and does not need to be |
2462 // create a return statement - this creates code in itself and does not need to be |
2725 // wrapped into an ExecuteNode |
2463 // wrapped into an ExecuteNode |
2726 final ReturnNode returnNode = new ReturnNode(source, expr.getToken(), finish, expr, null); |
2464 final ReturnNode returnNode = new ReturnNode(source, expr.getToken(), finish, expr); |
2727 |
2465 appendStatement(returnNode); |
2728 // add the return statement |
2466 lastToken = token; |
2729 functionNode.addStatement(returnNode); |
|
2730 functionNode.setLastToken(token); |
|
2731 functionNode.setFinish(Token.descPosition(token) + Token.descLength(token)); |
2467 functionNode.setFinish(Token.descPosition(token) + Token.descLength(token)); |
2732 |
2468 |
2733 } else { |
2469 } else { |
2734 expect(LBRACE); |
2470 expect(LBRACE); |
2735 |
2471 |
2736 // Gather the function elements. |
2472 // Gather the function elements. |
2737 final List<Node> prevFunctionDecls = functionDeclarations; |
2473 final List<Node> prevFunctionDecls = functionDeclarations; |
2738 functionDeclarations = new ArrayList<>(); |
2474 functionDeclarations = new ArrayList<>(); |
2739 try { |
2475 try { |
2740 sourceElements(); |
2476 sourceElements(); |
2741 functionNode.prependStatements(functionDeclarations); |
2477 addFunctionDeclarations(functionNode); |
2742 } finally { |
2478 } finally { |
2743 functionDeclarations = prevFunctionDecls; |
2479 functionDeclarations = prevFunctionDecls; |
2744 } |
2480 } |
2745 |
2481 |
2746 functionNode.setLastToken(token); |
2482 lastToken = token; |
2747 expect(RBRACE); |
2483 expect(RBRACE); |
2748 functionNode.setFinish(finish); |
2484 functionNode.setFinish(finish); |
2749 |
2485 |
2750 } |
2486 } |
2751 } finally { |
2487 } finally { |
2752 restoreBlock(functionNode); |
2488 functionNode = restoreFunctionNode(functionNode, lastToken); |
2753 } |
2489 } |
2754 |
|
2755 return functionNode; |
2490 return functionNode; |
|
2491 } |
|
2492 |
|
2493 private void addFunctionDeclarations(final FunctionNode functionNode) { |
|
2494 assert lc.peek() == lc.getFunctionBody(functionNode); |
|
2495 VarNode lastDecl = null; |
|
2496 for (int i = functionDeclarations.size() - 1; i >= 0; i--) { |
|
2497 Node decl = functionDeclarations.get(i); |
|
2498 if (lastDecl == null && decl instanceof VarNode) { |
|
2499 decl = lastDecl = ((VarNode)decl).setFlag(VarNode.IS_LAST_FUNCTION_DECLARATION); |
|
2500 lc.setFlag(functionNode, FunctionNode.HAS_FUNCTION_DECLARATIONS); |
|
2501 } |
|
2502 prependStatement(decl); |
|
2503 } |
2756 } |
2504 } |
2757 |
2505 |
2758 private RuntimeNode referenceError(final Node lhs, final Node rhs) { |
2506 private RuntimeNode referenceError(final Node lhs, final Node rhs) { |
2759 final ArrayList<Node> args = new ArrayList<>(); |
2507 final ArrayList<Node> args = new ArrayList<>(); |
2760 args.add(lhs); |
2508 args.add(lhs); |
2762 args.add(LiteralNode.newInstance(source, lhs.getToken(), lhs.getFinish())); |
2510 args.add(LiteralNode.newInstance(source, lhs.getToken(), lhs.getFinish())); |
2763 } else { |
2511 } else { |
2764 args.add(rhs); |
2512 args.add(rhs); |
2765 } |
2513 } |
2766 args.add(LiteralNode.newInstance(source, lhs.getToken(), lhs.getFinish(), lhs.toString())); |
2514 args.add(LiteralNode.newInstance(source, lhs.getToken(), lhs.getFinish(), lhs.toString())); |
2767 final RuntimeNode runtimeNode = new RuntimeNode(source, lhs.getToken(), |
2515 return new RuntimeNode(source, lhs.getToken(), lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args); |
2768 lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args); |
|
2769 return runtimeNode; |
|
2770 } |
2516 } |
2771 |
2517 |
2772 /* |
2518 /* |
2773 * parse LHS [a, b, ..., c]. |
2519 * parse LHS [a, b, ..., c]. |
2774 * |
2520 * |
3085 @Override |
2820 @Override |
3086 public String toString() { |
2821 public String toString() { |
3087 return "[JavaScript Parsing]"; |
2822 return "[JavaScript Parsing]"; |
3088 } |
2823 } |
3089 |
2824 |
3090 private Block getBlock() { |
2825 private static void markWithOrEval(final LexicalContext lc, int flag) { |
3091 return lexicalContext.getCurrentBlock(); |
2826 final Iterator<FunctionNode> iter = lc.getFunctions(); |
3092 } |
2827 boolean flaggedCurrentFn = false; |
3093 |
2828 while (iter.hasNext()) { |
3094 private FunctionNode getFunction() { |
2829 final FunctionNode fn = iter.next(); |
3095 return lexicalContext.getCurrentFunction(); |
2830 if (!flaggedCurrentFn) { |
|
2831 lc.setFlag(fn, flag); |
|
2832 flaggedCurrentFn = true; |
|
2833 } else { |
|
2834 lc.setFlag(fn, FunctionNode.HAS_DESCENDANT_WITH_OR_EVAL); |
|
2835 } |
|
2836 lc.setFlag(lc.getFunctionBody(fn), Block.NEEDS_SCOPE); |
|
2837 } |
|
2838 } |
|
2839 |
|
2840 private void prependStatement(final Node statement) { |
|
2841 lc.prependStatement(statement); |
|
2842 } |
|
2843 |
|
2844 private void appendStatement(final Node statement) { |
|
2845 lc.appendStatement(statement); |
3096 } |
2846 } |
3097 } |
2847 } |