aboutsummaryrefslogtreecommitdiff
path: root/src/jdk/nashorn/internal/parser/Parser.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/jdk/nashorn/internal/parser/Parser.java')
-rw-r--r--src/jdk/nashorn/internal/parser/Parser.java944
1 files changed, 346 insertions, 598 deletions
diff --git a/src/jdk/nashorn/internal/parser/Parser.java b/src/jdk/nashorn/internal/parser/Parser.java
index b810043e..ab70859b 100644
--- a/src/jdk/nashorn/internal/parser/Parser.java
+++ b/src/jdk/nashorn/internal/parser/Parser.java
@@ -54,24 +54,23 @@ import static jdk.nashorn.internal.parser.TokenType.TERNARY;
import static jdk.nashorn.internal.parser.TokenType.WHILE;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-import java.util.Stack;
import jdk.nashorn.internal.codegen.CompilerConstants;
import jdk.nashorn.internal.codegen.Namespace;
import jdk.nashorn.internal.ir.AccessNode;
import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Block;
+import jdk.nashorn.internal.ir.BlockLexicalContext;
import jdk.nashorn.internal.ir.BreakNode;
import jdk.nashorn.internal.ir.BreakableNode;
import jdk.nashorn.internal.ir.CallNode;
import jdk.nashorn.internal.ir.CaseNode;
import jdk.nashorn.internal.ir.CatchNode;
import jdk.nashorn.internal.ir.ContinueNode;
-import jdk.nashorn.internal.ir.DoWhileNode;
import jdk.nashorn.internal.ir.EmptyNode;
import jdk.nashorn.internal.ir.ExecuteNode;
import jdk.nashorn.internal.ir.ForNode;
@@ -84,6 +83,7 @@ import jdk.nashorn.internal.ir.LabelNode;
import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LineNumberNode;
import jdk.nashorn.internal.ir.LiteralNode;
+import jdk.nashorn.internal.ir.LoopNode;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.ObjectNode;
import jdk.nashorn.internal.ir.PropertyKey;
@@ -117,9 +117,10 @@ public class Parser extends AbstractParser {
/** Is scripting mode. */
private final boolean scripting;
- private final LexicalContext lexicalContext = new LexicalContext();
private List<Node> functionDeclarations;
+ private final BlockLexicalContext lc = new BlockLexicalContext();
+
/** Namespace for function names where not explicitly given */
private final Namespace namespace;
@@ -146,7 +147,7 @@ public class Parser extends AbstractParser {
*/
public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors, final boolean strict) {
super(source, errors, strict);
- this.env = env;
+ this.env = env;
this.namespace = new Namespace(env.getNamespace());
this.scripting = env._scripting;
}
@@ -162,7 +163,7 @@ public class Parser extends AbstractParser {
* @return function node resulting from successful parse
*/
public FunctionNode parse() {
- return parse(RUN_SCRIPT.tag());
+ return parse(RUN_SCRIPT.symbolName());
}
/**
@@ -176,7 +177,7 @@ public class Parser extends AbstractParser {
*/
public FunctionNode parse(final String scriptName) {
final long t0 = Timing.isEnabled() ? System.currentTimeMillis() : 0L;
- LOG.info(this + " begin for '" + scriptName + "'");
+ LOG.info(this, " begin for '", scriptName, "'");
try {
stream = new TokenStream();
@@ -214,7 +215,7 @@ public class Parser extends AbstractParser {
final String end = this + " end '" + scriptName + "'";
if (Timing.isEnabled()) {
Timing.accumulateTime(toString(), System.currentTimeMillis() - t0);
- LOG.info(end + "' in " + (System.currentTimeMillis() - t0) + " ms");
+ LOG.info(end, "' in ", (System.currentTimeMillis() - t0), " ms");
} else {
LOG.info(end);
}
@@ -275,8 +276,7 @@ loop:
*/
private Block newBlock() {
final Block block = new Block(source, token, Token.descPosition(token));
- lexicalContext.push(block);
- return block;
+ return lc.push(block);
}
/**
@@ -285,36 +285,60 @@ loop:
* @param ident Name of function.
* @return New block.
*/
- private FunctionNode newFunctionBlock(final IdentNode ident) {
+ private FunctionNode newFunctionNode(final long startToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind) {
// Build function name.
final StringBuilder sb = new StringBuilder();
- final FunctionNode parentFunction = getFunction();
- if(parentFunction != null && !parentFunction.isProgram()) {
+ final FunctionNode parentFunction = lc.getCurrentFunction();
+ if (parentFunction != null && !parentFunction.isProgram()) {
sb.append(parentFunction.getName()).append('$');
}
- sb.append(ident != null ? ident.getName() : FUNCTION_PREFIX.tag());
+ sb.append(ident != null ? ident.getName() : FUNCTION_PREFIX.symbolName());
final String name = namespace.uniqueName(sb.toString());
- assert parentFunction != null || name.equals(RUN_SCRIPT.tag()) : "name = " + name;// must not rename runScript().
+ assert parentFunction != null || name.equals(RUN_SCRIPT.symbolName()) : "name = " + name;// must not rename runScript().
- // Start new block.
- final FunctionNode functionBlock = new FunctionNode(source, token, Token.descPosition(token), namespace, ident, name);
- if(parentFunction == null) {
- functionBlock.setProgram();
+ int flags = 0;
+ if (parentFunction == null) {
+ flags |= FunctionNode.IS_PROGRAM;
+ }
+ if (isStrictMode) {
+ flags |= FunctionNode.IS_STRICT;
}
- functionBlock.setStrictMode(isStrictMode);
- functionBlock.setState(errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED);
- lexicalContext.push(functionBlock);
- return functionBlock;
+ // Start new block.
+ FunctionNode functionNode =
+ new FunctionNode(
+ source,
+ token,
+ Token.descPosition(token),
+ startToken,
+ namespace,
+ ident,
+ name,
+ parameters,
+ kind,
+ flags);
+
+ functionNode = functionNode.setState(lc, errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED);
+ lc.push(functionNode);
+ // Create new block, and just put it on the context stack, restoreFunctionNode() will associate it with the
+ // FunctionNode.
+ newBlock();
+ return functionNode;
}
/**
* Restore the current block.
*/
- private void restoreBlock(Block block) {
- lexicalContext.pop(block);
+ private Block restoreBlock(final Block block) {
+ return lc.pop(block);//.setFlag(lc, flags);
+ }
+
+ private FunctionNode restoreFunctionNode(final FunctionNode functionNode, final long lastToken) {
+ final Block newBody = restoreBlock(lc.getFunctionBody(functionNode));
+
+ return lc.pop(functionNode).setBody(lc, newBody).setLastToken(lc, lastToken);
}
/**
@@ -323,23 +347,17 @@ loop:
*/
private Block getBlock(final boolean needsBraces) {
// Set up new block. Captures LBRACE.
- final Block newBlock = newBlock();
+ Block newBlock = newBlock();
try {
- pushControlNode(newBlock);
-
// Block opening brace.
if (needsBraces) {
expect(LBRACE);
}
+ // Accumulate block statements.
+ statementList();
- try {
- // Accumulate block statements.
- statementList();
- } finally {
- popControlNode();
- }
} finally {
- restoreBlock(newBlock);
+ newBlock = restoreBlock(newBlock);
}
final int possibleEnd = Token.descPosition(token) + Token.descLength(token);
@@ -363,15 +381,12 @@ loop:
return getBlock(true);
}
// Set up new block. Captures first token.
- final Block newBlock = newBlock();
-
+ Block newBlock = newBlock();
try {
- // Accumulate statements.
statement();
} finally {
- restoreBlock(newBlock);
+ newBlock = restoreBlock(newBlock);
}
-
return newBlock;
}
@@ -382,11 +397,8 @@ loop:
private void detectSpecialFunction(final IdentNode ident) {
final String name = ident.getName();
- if (EVAL.tag().equals(name)) {
- final Iterator<FunctionNode> it = lexicalContext.getFunctions();
- if(it.hasNext()) {
- it.next().setHasEval(it);
- }
+ if (EVAL.symbolName().equals(name)) {
+ markEval(lc);
}
}
@@ -397,8 +409,8 @@ loop:
private void detectSpecialProperty(final IdentNode ident) {
final String name = ident.getName();
- if (ARGUMENTS.tag().equals(name)) {
- getFunction().setUsesArguments();
+ if (ARGUMENTS.symbolName().equals(name)) {
+ lc.setFlag(lc.getCurrentFunction(), FunctionNode.USES_ARGUMENTS);
}
}
@@ -439,7 +451,7 @@ loop:
lhs instanceof IndexNode ||
lhs instanceof IdentNode)) {
if (env._early_lvalue_error) {
- error(JSErrorType.REFERENCE_ERROR, AbstractParser.message("invalid.lvalue"), lhs.getToken());
+ throw error(JSErrorType.REFERENCE_ERROR, AbstractParser.message("invalid.lvalue"), lhs.getToken());
}
return referenceError(lhs, rhs);
}
@@ -469,143 +481,13 @@ loop:
* @return Reduced expression.
*/
private Node incDecExpression(final long firstToken, final TokenType tokenType, final Node expression, final boolean isPostfix) {
- long incDecToken = firstToken;
- if (isPostfix) {
- incDecToken = Token.recast(incDecToken, tokenType == DECPREFIX ? DECPOSTFIX : INCPOSTFIX);
- }
-
- final UnaryNode node = new UnaryNode(source, incDecToken, expression);
if (isPostfix) {
- node.setStart(expression.getStart());
- node.setFinish(Token.descPosition(incDecToken) + Token.descLength(incDecToken));
- }
-
- return node;
- }
-
- /**
- * Find a label node in the label stack.
- * @param ident Ident to find.
- * @return null or the found label node.
- */
- private LabelNode findLabel(final IdentNode ident) {
- for (final LabelNode labelNode : getFunction().getLabelStack()) {
- if (labelNode.getLabel().equals(ident)) {
- return labelNode;
- }
- }
-
- return null;
- }
-
- /**
- * Add a label to the label stack.
- * @param labelNode Label to add.
- */
- private void pushLabel(final LabelNode labelNode) {
- getFunction().getLabelStack().push(labelNode);
- }
-
- /**
- * Remove a label from the label stack.
- */
- private void popLabel() {
- getFunction().getLabelStack().pop();
- }
-
- /**
- * Track the current nesting of controls for break and continue.
- * @param node For, while, do or switch node.
- */
- private void pushControlNode(final Node node) {
- final boolean isLoop = node instanceof WhileNode;
- final boolean isBreakable = node instanceof BreakableNode || node instanceof Block;
- final FunctionNode function = getFunction();
- function.getControlStack().push(node);
-
- for (final LabelNode labelNode : function.getLabelStack()) {
- if (isBreakable && labelNode.getBreakNode() == null) {
- labelNode.setBreakNode(node);
- }
-
- if (isLoop && labelNode.getContinueNode() == null) {
- labelNode.setContinueNode(node);
- }
- }
- }
-
- /**
- * Finish with control.
- */
- private void popControlNode() {
- // Get control stack.
- final Stack<Node> controlStack = getFunction().getControlStack();
-
- // Can be empty if missing brace.
- if (!controlStack.isEmpty()) {
- controlStack.pop();
- }
- }
-
- private void popControlNode(final Node node) {
- // Get control stack.
- final Stack<Node> controlStack = getFunction().getControlStack();
-
- // Can be empty if missing brace.
- if (!controlStack.isEmpty() && controlStack.peek() == node) {
- controlStack.pop();
- }
- }
-
- private boolean isInWithBlock() {
- final Stack<Node> controlStack = getFunction().getControlStack();
- for (int i = controlStack.size() - 1; i >= 0; i--) {
- final Node node = controlStack.get(i);
-
- if (node instanceof WithNode) {
- return true;
- }
- }
-
- return false;
- }
-
- private <T extends Node> T findControl(final Class<T> ctype) {
- final Stack<Node> controlStack = getFunction().getControlStack();
- for (int i = controlStack.size() - 1; i >= 0; i--) {
- final Node node = controlStack.get(i);
-
- if (ctype.isAssignableFrom(node.getClass())) {
- return ctype.cast(node);
- }
- }
-
- return null;
- }
-
- private <T extends Node> List<T> findControls(final Class<T> ctype, final Node to) {
- final List<T> nodes = new ArrayList<>();
- final Stack<Node> controlStack = getFunction().getControlStack();
- for (int i = controlStack.size() - 1; i >= 0; i--) {
- final Node node = controlStack.get(i);
-
- if (to == node) {
- break; //stop looking
- }
-
- if (ctype.isAssignableFrom(node.getClass())) {
- nodes.add(ctype.cast(node));
- }
+ return new UnaryNode(source, Token.recast(firstToken, tokenType == DECPREFIX ? DECPOSTFIX : INCPOSTFIX), expression.getStart(), Token.descPosition(firstToken) + Token.descLength(firstToken), expression);
}
- return nodes;
+ return new UnaryNode(source, firstToken, expression);
}
- private <T extends Node> int countControls(final Class<T> ctype, final Node to) {
- return findControls(ctype, to).size();
- }
-
-
/**
* -----------------------------------------------------------------------
*
@@ -630,18 +512,23 @@ loop:
final long functionToken = Token.toDesc(FUNCTION, 0, source.getLength());
// Set up the script to append elements.
- final FunctionNode script = newFunctionBlock(new IdentNode(source, functionToken, Token.descPosition(functionToken), scriptName));
+ FunctionNode script = newFunctionNode(
+ functionToken,
+ new IdentNode(source, functionToken, Token.descPosition(functionToken), scriptName),
+ new ArrayList<IdentNode>(),
+ FunctionNode.Kind.SCRIPT);
- script.setKind(FunctionNode.Kind.SCRIPT);
- script.setFirstToken(functionToken);
functionDeclarations = new ArrayList<>();
sourceElements();
- script.prependStatements(functionDeclarations);
+ addFunctionDeclarations(script);
functionDeclarations = null;
+
expect(EOF);
- script.setLastToken(token);
+
script.setFinish(source.getLength() - 1);
+ script = restoreFunctionNode(script, token); //commit code
+ script = script.setBody(lc, script.getBody().setNeedsScope(lc));
return script;
}
@@ -670,24 +557,6 @@ loop:
}
/**
- * Return last node in a statement list.
- *
- * @param statements Statement list.
- *
- * @return Last (non-debug) statement or null if empty block.
- */
- private static Node lastStatement(final List<Node> statements) {
- for (int lastIndex = statements.size() - 1; lastIndex >= 0; lastIndex--) {
- final Node node = statements.get(lastIndex);
- if (!node.isDebug()) {
- return node;
- }
- }
-
- return null;
- }
-
- /**
* SourceElements :
* SourceElement
* SourceElements SourceElement
@@ -716,7 +585,7 @@ loop:
// check for directive prologues
if (checkDirective) {
// skip any debug statement like line number to get actual first line
- final Node lastStatement = lastStatement(getBlock().getStatements());
+ final Node lastStatement = lc.getLastStatement();
// get directive prologue, if any
final String directive = getDirective(lastStatement);
@@ -736,8 +605,8 @@ loop:
// handle use strict directive
if ("use strict".equals(directive)) {
isStrictMode = true;
- final FunctionNode function = getFunction();
- function.setStrictMode(true);
+ final FunctionNode function = lc.getCurrentFunction();
+ lc.setFlag(lc.getCurrentFunction(), FunctionNode.IS_STRICT);
// We don't need to check these, if lexical environment is already strict
if (!oldStrictMode && directiveStmts != null) {
@@ -759,7 +628,7 @@ loop:
}
}
} catch (final Exception e) {
- // Recover parsing.
+ //recover parsing
recover(e);
}
@@ -806,14 +675,13 @@ loop:
if (type == FUNCTION) {
// As per spec (ECMA section 12), function declarations as arbitrary statement
// is not "portable". Implementation can issue a warning or disallow the same.
- if (isStrictMode && !topLevel) {
- error(AbstractParser.message("strict.no.func.here"), token);
- }
functionExpression(true, topLevel);
return;
}
- getBlock().addStatement(lineNumberNode);
+ if (lineNumberNode != null) {
+ appendStatement(lineNumberNode);
+ }
switch (type) {
case LBRACE:
@@ -893,13 +761,9 @@ loop:
* Parse a statement block.
*/
private void block() {
- // Get statements in block.
final Block newBlock = getBlock(true);
-
// Force block execution.
- final ExecuteNode executeNode = new ExecuteNode(source, newBlock.getToken(), finish, newBlock);
-
- getBlock().addStatement(executeNode);
+ appendStatement(new ExecuteNode(source, newBlock.getToken(), finish, newBlock));
}
/**
@@ -942,7 +806,7 @@ loop:
switch (ident.getName()) {
case "eval":
case "arguments":
- error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken());
+ throw error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken());
default:
break;
}
@@ -995,8 +859,7 @@ loop:
// Allocate var node.
final VarNode var = new VarNode(source, varToken, finish, name, init);
vars.add(var);
- // Add to current block.
- getBlock().addStatement(var);
+ appendStatement(var);
if (type != COMMARIGHT) {
break;
@@ -1009,7 +872,7 @@ loop:
boolean semicolon = type == SEMICOLON;
endOfLine();
if (semicolon) {
- getBlock().setFinish(finish);
+ lc.getCurrentBlock().setFinish(finish);
}
}
@@ -1026,8 +889,7 @@ loop:
*/
private void emptyStatement() {
if (env._empty_statements) {
- getBlock().addStatement(new EmptyNode(source, token,
- Token.descPosition(token) + Token.descLength(token)));
+ appendStatement(new EmptyNode(source, token, Token.descPosition(token) + Token.descLength(token)));
}
// SEMICOLON checked in caller.
@@ -1052,7 +914,7 @@ loop:
ExecuteNode executeNode = null;
if (expression != null) {
executeNode = new ExecuteNode(source, expressionToken, finish, expression);
- getBlock().addStatement(executeNode);
+ appendStatement(executeNode);
} else {
expect(null);
}
@@ -1061,7 +923,7 @@ loop:
if (executeNode != null) {
executeNode.setFinish(finish);
- getBlock().setFinish(finish);
+ lc.getCurrentBlock().setFinish(finish);
}
}
@@ -1081,29 +943,17 @@ loop:
next();
expect(LPAREN);
-
- // Get the test expression.
final Node test = expression();
-
expect(RPAREN);
-
- // Get the pass statement.
final Block pass = getStatement();
- // Assume no else.
Block fail = null;
-
if (type == ELSE) {
next();
-
- // Get the else block.
fail = getStatement();
}
- // Construct and add new if node.
- final IfNode ifNode = new IfNode(source, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail);
-
- getBlock().addStatement(ifNode);
+ appendStatement(new IfNode(source, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail));
}
/**
@@ -1120,12 +970,12 @@ loop:
*/
private void forStatement() {
// Create FOR node, capturing FOR token.
- final ForNode forNode = new ForNode(source, token, Token.descPosition(token));
+ ForNode forNode = new ForNode(source, token, Token.descPosition(token), null, null, null, null, ForNode.IS_FOR);
- pushControlNode(forNode);
// Set up new block for scope of vars. Captures first token.
- final Block outer = newBlock();
+ Block outer = newBlock();
+ lc.push(forNode);
try {
// FOR tested in caller.
@@ -1134,31 +984,97 @@ loop:
// Nashorn extension: for each expression.
// iterate property values rather than property names.
if (!env._no_syntax_extensions && type == IDENT && "each".equals(getValue())) {
- forNode.setIsForEach();
+ forNode = forNode.setIsForEach(lc);
next();
}
expect(LPAREN);
- /// Capture control information.
- forControl(forNode);
+ List<VarNode> vars = null;
+
+ switch (type) {
+ case VAR:
+ // Var statements captured in for outer block.
+ vars = variableStatement(false);
+ break;
+ case SEMICOLON:
+ break;
+ default:
+ final Node expression = expression(unaryExpression(), COMMARIGHT.getPrecedence(), true);
+ forNode = forNode.setInit(lc, expression);
+ break;
+ }
+
+ switch (type) {
+ case SEMICOLON:
+ // for (init; test; modify)
+ expect(SEMICOLON);
+ if (type != SEMICOLON) {
+ forNode = forNode.setTest(lc, expression());
+ }
+ expect(SEMICOLON);
+ if (type != RPAREN) {
+ forNode = forNode.setModify(lc, expression());
+ }
+ break;
+
+ case IN:
+ forNode = forNode.setIsForIn(lc);
+ if (vars != null) {
+ // for (var i in obj)
+ if (vars.size() == 1) {
+ forNode = forNode.setInit(lc, new IdentNode(vars.get(0).getName()));
+ } else {
+ // for (var i, j in obj) is invalid
+ throw error(AbstractParser.message("many.vars.in.for.in.loop"), vars.get(1).getToken());
+ }
+
+ } else {
+ // for (expr in obj)
+ final Node init = forNode.getInit();
+ assert init != null : "for..in init expression can not be null here";
+
+ // check if initial expression is a valid L-value
+ if (!(init instanceof AccessNode ||
+ init instanceof IndexNode ||
+ init instanceof IdentNode)) {
+ throw error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken());
+ }
+
+ if (init instanceof IdentNode) {
+ if (!checkIdentLValue((IdentNode)init)) {
+ throw error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken());
+ }
+ verifyStrictIdent((IdentNode)init, "for-in iterator");
+ }
+ }
+
+ next();
+
+ // Get the collection expression.
+ forNode = forNode.setModify(lc, expression());
+ break;
+
+ default:
+ expect(SEMICOLON);
+ break;
+ }
expect(RPAREN);
// Set the for body.
final Block body = getStatement();
- forNode.setBody(body);
+ forNode = forNode.setBody(lc, body);
forNode.setFinish(body.getFinish());
outer.setFinish(body.getFinish());
- // Add for to current block.
- getBlock().addStatement(forNode);
+ appendStatement(forNode);
} finally {
- restoreBlock(outer);
- popControlNode();
+ lc.pop(forNode);
+ outer = restoreBlock(outer);
}
- getBlock().addStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
+ appendStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
}
/**
@@ -1175,87 +1091,7 @@ loop:
* comprehensions.
* @param forNode Owning FOR.
*/
- private void forControl(final ForNode forNode) {
- List<VarNode> vars = null;
-
- switch (type) {
- case VAR:
- // Var statements captured in for outer block.
- vars = variableStatement(false);
- break;
-
- case SEMICOLON:
- break;
-
- default:
- final Node expression = expression(unaryExpression(), COMMARIGHT.getPrecedence(), true);
- forNode.setInit(expression);
- }
-
- switch (type) {
- case SEMICOLON:
- // for (init; test; modify)
- expect(SEMICOLON);
-
- // Get the test expression.
- if (type != SEMICOLON) {
- forNode.setTest(expression());
- }
-
- expect(SEMICOLON);
-
- // Get the modify expression.
- if (type != RPAREN) {
- final Node expression = expression();
- forNode.setModify(expression);
- }
-
- break;
-
- case IN:
- forNode.setIsForIn();
- if (vars != null) {
- // for (var i in obj)
- if (vars.size() == 1) {
- forNode.setInit(new IdentNode(vars.get(0).getName()));
- } else {
- // for (var i, j in obj) is invalid
- error(AbstractParser.message("many.vars.in.for.in.loop"), vars.get(1).getToken());
- }
-
- } else {
- // for (expr in obj)
- final Node init = forNode.getInit();
- assert init != null : "for..in init expression can not be null here";
-
- // check if initial expression is a valid L-value
- if (!(init instanceof AccessNode ||
- init instanceof IndexNode ||
- init instanceof IdentNode)) {
- error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken());
- }
-
- if (init instanceof IdentNode) {
- if (!checkIdentLValue((IdentNode)init)) {
- error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken());
- }
- verifyStrictIdent((IdentNode)init, "for-in iterator");
- }
- }
-
- next();
-
- // Get the collection expression.
- forNode.setModify(expression());
- break;
-
- default:
- expect(SEMICOLON);
- break;
- }
-
- }
/**
* ...IterationStatement :
@@ -1274,27 +1110,17 @@ loop:
next();
// Construct WHILE node.
- final WhileNode whileNode = new WhileNode(source, whileToken, Token.descPosition(whileToken));
- pushControlNode(whileNode);
+ WhileNode whileNode = new WhileNode(source, whileToken, Token.descPosition(whileToken), false);
+ lc.push(whileNode);
try {
expect(LPAREN);
-
- // Get the test expression.
- final Node test = expression();
- whileNode.setTest(test);
-
+ whileNode = whileNode.setTest(lc, expression());
expect(RPAREN);
-
- // Get WHILE body.
- final Block statements = getStatement();
- whileNode.setBody(statements);
- whileNode.setFinish(statements.getFinish());
-
- // Add WHILE node.
- getBlock().addStatement(whileNode);
+ whileNode = whileNode.setBody(lc, getStatement());
+ appendStatement(whileNode);
} finally {
- popControlNode();
+ lc.pop(whileNode);
}
}
@@ -1314,34 +1140,25 @@ loop:
// DO tested in the caller.
next();
- final WhileNode doWhileNode = new DoWhileNode(source, doToken, Token.descPosition(doToken));
- pushControlNode(doWhileNode);
+ WhileNode doWhileNode = new WhileNode(source, doToken, Token.descPosition(doToken), true);
+ lc.push(doWhileNode);
try {
// Get DO body.
- final Block statements = getStatement();
- doWhileNode.setBody(statements);
+ doWhileNode = doWhileNode.setBody(lc, getStatement());
expect(WHILE);
-
expect(LPAREN);
-
- // Get the test expression.
- final Node test = expression();
- doWhileNode.setTest(test);
-
+ doWhileNode = doWhileNode.setTest(lc, expression());
expect(RPAREN);
if (type == SEMICOLON) {
endOfLine();
}
-
doWhileNode.setFinish(finish);
-
- // Add DO node.
- getBlock().addStatement(doWhileNode);
+ appendStatement(doWhileNode);
} finally {
- popControlNode();
+ lc.pop(doWhileNode);
}
}
@@ -1370,28 +1187,26 @@ loop:
default:
final IdentNode ident = getIdent();
- labelNode = findLabel(ident);
+ labelNode = lc.findLabel(ident.getName());
if (labelNode == null) {
- error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken());
+ throw error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken());
}
break;
}
- final Node targetNode = labelNode != null ? labelNode.getContinueNode() : findControl(WhileNode.class);
+ final IdentNode label = labelNode == null ? null : labelNode.getLabel();
+ final LoopNode targetNode = lc.getContinueTo(label);
if (targetNode == null) {
- error(AbstractParser.message("illegal.continue.stmt"), continueToken);
+ throw error(AbstractParser.message("illegal.continue.stmt"), continueToken);
}
endOfLine();
// Construct and add CONTINUE node.
- final ContinueNode continueNode = new ContinueNode(source, continueToken, finish, labelNode, targetNode, findControl(TryNode.class));
- continueNode.setScopeNestingLevel(countControls(WithNode.class, targetNode));
-
- getBlock().addStatement(continueNode);
+ appendStatement(new ContinueNode(source, continueToken, finish, label == null ? null : new IdentNode(label)));
}
/**
@@ -1418,28 +1233,27 @@ loop:
default:
final IdentNode ident = getIdent();
- labelNode = findLabel(ident);
+ labelNode = lc.findLabel(ident.getName());
if (labelNode == null) {
- error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken());
+ throw error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken());
}
break;
}
- final Node targetNode = labelNode != null ? labelNode.getBreakNode() : findControl(BreakableNode.class);
-
+ //either an explicit label - then get its node or just a "break" - get first breakable
+ //targetNode is what we are breaking out from.
+ final IdentNode label = labelNode == null ? null : labelNode.getLabel();
+ final BreakableNode targetNode = lc.getBreakable(label);
if (targetNode == null) {
- error(AbstractParser.message("illegal.break.stmt"), breakToken);
+ throw error(AbstractParser.message("illegal.break.stmt"), breakToken);
}
endOfLine();
// Construct and add BREAK node.
- final BreakNode breakNode = new BreakNode(source, breakToken, finish, labelNode, targetNode, findControl(TryNode.class));
- breakNode.setScopeNestingLevel(countControls(WithNode.class, targetNode));
-
- getBlock().addStatement(breakNode);
+ appendStatement(new BreakNode(source, breakToken, finish, label == null ? null : new IdentNode(label)));
}
/**
@@ -1452,8 +1266,8 @@ loop:
*/
private void returnStatement() {
// check for return outside function
- if (getFunction().getKind() == FunctionNode.Kind.SCRIPT) {
- error(AbstractParser.message("invalid.return"));
+ if (lc.getCurrentFunction().getKind() == FunctionNode.Kind.SCRIPT) {
+ throw error(AbstractParser.message("invalid.return"));
}
// Capture RETURN token.
@@ -1478,8 +1292,7 @@ loop:
endOfLine();
// Construct and add RETURN node.
- final ReturnNode returnNode = new ReturnNode(source, returnToken, finish, expression, findControl(TryNode.class));
- getBlock().addStatement(returnNode);
+ appendStatement(new ReturnNode(source, returnToken, finish, expression));
}
/**
@@ -1513,8 +1326,7 @@ loop:
endOfLine();
// Construct and add YIELD node.
- final ReturnNode yieldNode = new ReturnNode(source, yieldToken, finish, expression, findControl(TryNode.class));
- getBlock().addStatement(yieldNode);
+ appendStatement(new ReturnNode(source, yieldToken, finish, expression));
}
/**
@@ -1533,35 +1345,23 @@ loop:
// ECMA 12.10.1 strict mode restrictions
if (isStrictMode) {
- error(AbstractParser.message("strict.no.with"), withToken);
+ throw error(AbstractParser.message("strict.no.with"), withToken);
}
// Get WITH expression.
- final WithNode withNode = new WithNode(source, withToken, finish, null, null);
- final Iterator<FunctionNode> it = lexicalContext.getFunctions();
- if(it.hasNext()) {
- it.next().setHasWith(it);
- }
+ WithNode withNode = new WithNode(source, withToken, finish);
try {
- pushControlNode(withNode);
-
+ lc.push(withNode);
expect(LPAREN);
-
- final Node expression = expression();
- withNode.setExpression(expression);
-
+ withNode = withNode.setExpression(lc, expression());
expect(RPAREN);
-
- // Get WITH body.
- final Block statements = getStatement();
- withNode.setBody(statements);
- withNode.setFinish(finish);
+ withNode = withNode.setBody(lc, getStatement());
} finally {
- popControlNode(withNode);
+ lc.pop(withNode);
}
- getBlock().addStatement(withNode);
+ appendStatement(withNode);
}
/**
@@ -1587,22 +1387,17 @@ loop:
* Parse SWITCH statement.
*/
private void switchStatement() {
- // Capture SWITCH token.
final long switchToken = token;
// SWITCH tested in caller.
next();
// Create and add switch statement.
- final SwitchNode switchNode = new SwitchNode(source, switchToken, Token.descPosition(switchToken));
- pushControlNode(switchNode);
+ SwitchNode switchNode = new SwitchNode(source, switchToken, Token.descPosition(switchToken), null, new ArrayList<CaseNode>(), null);
+ lc.push(switchNode);
try {
expect(LPAREN);
-
- // Get switch expression.
- final Node switchExpression = expression();
- switchNode.setExpression(switchExpression);
-
+ switchNode = switchNode.setExpression(lc, expression());
expect(RPAREN);
expect(LBRACE);
@@ -1619,19 +1414,14 @@ loop:
switch (type) {
case CASE:
next();
-
- // Get case expression.
caseExpression = expression();
-
break;
case DEFAULT:
if (defaultCase != null) {
- error(AbstractParser.message("duplicate.default.in.switch"));
+ throw error(AbstractParser.message("duplicate.default.in.switch"));
}
-
next();
-
break;
default:
@@ -1654,16 +1444,13 @@ loop:
cases.add(caseNode);
}
- switchNode.setCases(cases);
- switchNode.setDefaultCase(defaultCase);
-
+ switchNode = switchNode.setCases(lc, cases, defaultCase);
next();
-
switchNode.setFinish(finish);
- getBlock().addStatement(switchNode);
+ appendStatement(switchNode);
} finally {
- popControlNode();
+ lc.pop(switchNode);
}
}
@@ -1683,23 +1470,19 @@ loop:
expect(COLON);
- if (findLabel(ident) != null) {
- error(AbstractParser.message("duplicate.label", ident.getName()), labelToken);
+ if (lc.findLabel(ident.getName()) != null) {
+ throw error(AbstractParser.message("duplicate.label", ident.getName()), labelToken);
}
+ LabelNode labelNode = new LabelNode(source, labelToken, finish, ident, null);
try {
- // Create and add label.
- final LabelNode labelNode = new LabelNode(source, labelToken, finish, ident, null);
- pushLabel(labelNode);
- // Get and save body.
- final Block statements = getStatement();
- labelNode.setBody(statements);
+ lc.push(labelNode);
+ labelNode = labelNode.setBody(lc, getStatement());
labelNode.setFinish(finish);
-
- getBlock().addStatement(labelNode);
+ appendStatement(labelNode);
} finally {
- // Remove label.
- popLabel();
+ assert lc.peek() instanceof LabelNode;
+ lc.pop(labelNode);
}
}
@@ -1732,14 +1515,12 @@ loop:
}
if (expression == null) {
- error(AbstractParser.message("expected.operand", type.getNameOrType()));
+ throw error(AbstractParser.message("expected.operand", type.getNameOrType()));
}
endOfLine();
- // Construct and add THROW node.
- final ThrowNode throwNode = new ThrowNode(source, throwToken, finish, expression, findControl(TryNode.class));
- getBlock().addStatement(throwNode);
+ appendStatement(new ThrowNode(source, throwToken, finish, expression));
}
/**
@@ -1766,28 +1547,18 @@ loop:
next();
// Container block needed to act as target for labeled break statements
- final Block outer = newBlock();
- pushControlNode(outer);
+ Block outer = newBlock();
// Create try.
- final TryNode tryNode = new TryNode(source, tryToken, Token.descPosition(tryToken), findControl(TryNode.class));
- pushControlNode(tryNode);
try {
- // Get TRY body.
- final Block tryBody = getBlock(true);
-
- // Prepare to accumulate catches.
+ final Block tryBody = getBlock(true);
final List<Block> catchBlocks = new ArrayList<>();
while (type == CATCH) {
- // Capture CATCH token.
final long catchToken = token;
next();
-
expect(LPAREN);
-
- // Get exception ident.
final IdentNode exception = getIdent();
// ECMA 12.4.1 strict mode restrictions
@@ -1795,28 +1566,23 @@ loop:
// Check for conditional catch.
Node ifExpression = null;
-
if (type == IF) {
next();
-
// Get the exception condition.
ifExpression = expression();
}
expect(RPAREN);
- final Block catchBlock = newBlock();
+ Block catchBlock = newBlock();
try {
-
// Get CATCH body.
final Block catchBody = getBlock(true);
-
- // Create and add catch.
final CatchNode catchNode = new CatchNode(source, catchToken, finish, exception, ifExpression, catchBody);
- getBlock().addStatement(catchNode);
- catchBlocks.add(catchBlock);
+ appendStatement(catchNode);
} finally {
- restoreBlock(catchBlock);
+ catchBlock = restoreBlock(catchBlock);
+ catchBlocks.add(catchBlock);
}
// If unconditional catch then should to be the end.
@@ -1825,38 +1591,32 @@ loop:
}
}
- popControlNode();
-
// Prepare to capture finally statement.
Block finallyStatements = null;
if (type == FINALLY) {
next();
-
- // Get FINALLY body.
finallyStatements = getBlock(true);
}
// Need at least one catch or a finally.
if (catchBlocks.isEmpty() && finallyStatements == null) {
- error(AbstractParser.message("missing.catch.or.finally"), tryToken);
+ throw error(AbstractParser.message("missing.catch.or.finally"), tryToken);
}
- tryNode.setBody(tryBody);
- tryNode.setCatchBlocks(catchBlocks);
- tryNode.setFinallyBody(finallyStatements);
+ final TryNode tryNode = new TryNode(source, tryToken, Token.descPosition(tryToken), tryBody, catchBlocks, finallyStatements);
+ // Add try.
+ assert lc.peek() == outer;
+ appendStatement(tryNode);
+
tryNode.setFinish(finish);
outer.setFinish(finish);
- // Add try.
- outer.addStatement(tryNode);
} finally {
- popControlNode(tryNode);
- restoreBlock(outer);
- popControlNode(outer);
+ outer = restoreBlock(outer);
}
- getBlock().addStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
+ appendStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
}
/**
@@ -1872,11 +1632,8 @@ loop:
final long debuggerToken = token;
// DEBUGGER tested in caller.
next();
-
endOfLine();
-
- final RuntimeNode runtimeNode = new RuntimeNode(source, debuggerToken, finish, RuntimeNode.Request.DEBUGGER, new ArrayList<Node>());
- getBlock().addStatement(runtimeNode);
+ appendStatement(new RuntimeNode(source, debuggerToken, finish, RuntimeNode.Request.DEBUGGER, new ArrayList<Node>()));
}
/**
@@ -1912,7 +1669,7 @@ loop:
return ident;
case OCTAL:
if (isStrictMode) {
- error(AbstractParser.message("strict.no.octal"), token);
+ throw error(AbstractParser.message("strict.no.octal"), token);
}
case STRING:
case ESCSTRING:
@@ -2036,7 +1793,7 @@ loop:
default:
if (!elision) {
- error(AbstractParser.message("expected.comma", type.getNameOrType()));
+ throw error(AbstractParser.message("expected.comma", type.getNameOrType()));
}
// Add expression element.
final Node expression = assignmentExpression(false);
@@ -2077,8 +1834,8 @@ loop:
// Object context.
// Prepare to accumulate elements.
- final List<Node> elements = new ArrayList<>();
- final Map<Object, PropertyNode> map = new HashMap<>();
+ // final List<Node> elements = new ArrayList<>();
+ final Map<String, PropertyNode> map = new LinkedHashMap<>();
// Create a block for the object literal.
boolean commaSeen = true;
@@ -2096,25 +1853,30 @@ loop:
default:
if (!commaSeen) {
- error(AbstractParser.message("expected.comma", type.getNameOrType()));
- }
+ throw error(AbstractParser.message("expected.comma", type.getNameOrType()));
+ }
- commaSeen = false;
- // Get and add the next property.
- final PropertyNode property = propertyAssignment();
- final Object key = property.getKeyName();
- final PropertyNode existingProperty = map.get(key);
+ commaSeen = false;
+ // Get and add the next property.
+ final PropertyNode property = propertyAssignment();
+ final String key = property.getKeyName();
+ final PropertyNode existingProperty = map.get(key);
+
+ if (existingProperty == null) {
+ map.put(key, property);
+ // elements.add(property);
+ break;
+ }
- if (existingProperty != null) {
// ECMA section 11.1.5 Object Initialiser
// point # 4 on property assignment production
- final Node value = property.getValue();
- final Node getter = property.getGetter();
- final Node setter = property.getSetter();
+ final Node value = property.getValue();
+ final FunctionNode getter = property.getGetter();
+ final FunctionNode setter = property.getSetter();
- final Node prevValue = existingProperty.getValue();
- final Node prevGetter = existingProperty.getGetter();
- final Node prevSetter = existingProperty.getSetter();
+ final Node prevValue = existingProperty.getValue();
+ final FunctionNode prevGetter = existingProperty.getGetter();
+ final FunctionNode prevSetter = existingProperty.getSetter();
boolean redefinitionOk = true;
// ECMA 11.1.5 strict mode restrictions
@@ -2125,7 +1887,7 @@ loop:
}
final boolean isPrevAccessor = prevGetter != null || prevSetter != null;
- final boolean isAccessor = getter != null || setter != null;
+ final boolean isAccessor = getter != null || setter != null;
// data property redefined as accessor property
if (prevValue != null && isAccessor) {
@@ -2145,40 +1907,33 @@ loop:
}
if (!redefinitionOk) {
- error(AbstractParser.message("property.redefinition", key.toString()), property.getToken());
+ throw error(AbstractParser.message("property.redefinition", key.toString()), property.getToken());
}
+ PropertyNode newProperty = existingProperty;
if (value != null) {
- final Node existingValue = existingProperty.getValue();
-
- if (existingValue == null) {
- existingProperty.setValue(value);
+ if (prevValue == null) {
+ map.put(key, newProperty = newProperty.setValue(value));
} else {
- final long propertyToken = Token.recast(existingProperty.getToken(), COMMARIGHT);
- existingProperty.setValue(new BinaryNode(source, propertyToken, existingValue, value));
+ final long propertyToken = Token.recast(newProperty.getToken(), COMMARIGHT);
+ map.put(key, newProperty = newProperty.setValue(new BinaryNode(source, propertyToken, prevValue, value)));
}
- existingProperty.setGetter(null);
- existingProperty.setSetter(null);
+ map.put(key, newProperty = newProperty.setGetter(null).setSetter(null));
}
if (getter != null) {
- existingProperty.setGetter(getter);
+ map.put(key, newProperty = newProperty.setGetter(getter));
}
if (setter != null) {
- existingProperty.setSetter(setter);
+ map.put(key, newProperty = newProperty.setSetter(setter));
}
- } else {
- map.put(key, property);
- elements.add(property);
- }
-
- break;
+ break;
}
}
- return new ObjectNode(source, objectToken, finish, elements);
+ return new ObjectNode(source, objectToken, finish, new ArrayList<Node>(map.values()));
}
/**
@@ -2198,7 +1953,7 @@ loop:
return getIdent();
case OCTAL:
if (isStrictMode) {
- error(AbstractParser.message("strict.no.octal"), token);
+ throw error(AbstractParser.message("strict.no.octal"), token);
}
case STRING:
case ESCSTRING:
@@ -2235,8 +1990,6 @@ loop:
final long propertyToken = token;
FunctionNode functionNode;
- List<IdentNode> parameters;
- PropertyNode propertyNode;
PropertyKey propertyName;
if (type == IDENT) {
@@ -2253,11 +2006,8 @@ loop:
final IdentNode getNameNode = new IdentNode(source, ((Node)getIdent).getToken(), finish, "get " + getterName);
expect(LPAREN);
expect(RPAREN);
- parameters = new ArrayList<>();
- functionNode = functionBody(getSetToken, getNameNode, parameters, FunctionNode.Kind.GETTER);
- propertyNode = new PropertyNode(source, propertyToken, finish, getIdent, null);
- propertyNode.setGetter(functionNode);
- return propertyNode;
+ functionNode = functionBody(getSetToken, getNameNode, new ArrayList<IdentNode>(), FunctionNode.Kind.GETTER);
+ return new PropertyNode(source, propertyToken, finish, getIdent, null, functionNode, null);
case "set":
final PropertyKey setIdent = propertyName();
@@ -2267,12 +2017,10 @@ loop:
final IdentNode argIdent = getIdent();
verifyStrictIdent(argIdent, "setter argument");
expect(RPAREN);
- parameters = new ArrayList<>();
+ List<IdentNode> parameters = new ArrayList<>();
parameters.add(argIdent);
functionNode = functionBody(getSetToken, setNameNode, parameters, FunctionNode.Kind.SETTER);
- propertyNode = new PropertyNode(source, propertyToken, finish, setIdent, null);
- propertyNode.setSetter(functionNode);
- return propertyNode;
+ return new PropertyNode(source, propertyToken, finish, setIdent, null, null, functionNode);
default:
break;
@@ -2286,9 +2034,7 @@ loop:
expect(COLON);
- final Node value = assignmentExpression(false);
- propertyNode = new PropertyNode(source, propertyToken, finish, propertyName, value);
- return propertyNode;
+ return new PropertyNode(source, propertyToken, finish, propertyName, assignmentExpression(false), null, null);
}
/**
@@ -2321,9 +2067,6 @@ loop:
}
lhs = new CallNode(source, callToken, finish, lhs, arguments);
- if (isInWithBlock()) {
- ((CallNode)lhs).setInWithBlock();
- }
}
loop:
@@ -2338,9 +2081,6 @@ loop:
// Create call node.
lhs = new CallNode(source, callToken, finish, lhs, arguments);
- if (isInWithBlock()) {
- ((CallNode)lhs).setInWithBlock();
- }
break;
@@ -2420,9 +2160,6 @@ loop:
}
final CallNode callNode = new CallNode(source, constructor.getToken(), finish, constructor, arguments);
- if (isInWithBlock()) {
- callNode.setInWithBlock();
- }
return new UnaryNode(source, newToken, callNode);
}
@@ -2482,8 +2219,7 @@ loop:
case PERIOD:
if (lhs == null) {
- error(AbstractParser.message("expected.operand", type.getNameOrType()));
- return null;
+ throw error(AbstractParser.message("expected.operand", type.getNameOrType()));
}
next();
@@ -2585,29 +2321,33 @@ loop:
}
expect(LPAREN);
-
final List<IdentNode> parameters = formalParameterList();
-
expect(RPAREN);
- final FunctionNode functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL);
+ FunctionNode functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL);
if (isStatement) {
- if(topLevel) {
- functionNode.setIsDeclared();
+ if (topLevel) {
+ functionNode = functionNode.setFlag(lc, FunctionNode.IS_DECLARED);
+ } else if (isStrictMode) {
+ throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("strict.no.func.decl.here"), functionToken);
+ } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.ERROR) {
+ throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here"), functionToken);
+ } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.WARNING) {
+ warning(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here.warn"), functionToken);
}
- if(ARGUMENTS.tag().equals(name.getName())) {
- getFunction().setDefinesArguments();
+ if (ARGUMENTS.symbolName().equals(name.getName())) {
+ lc.setFlag(lc.getCurrentFunction(), FunctionNode.DEFINES_ARGUMENTS);
}
}
if (isAnonymous) {
- functionNode.setIsAnonymous();
+ functionNode = functionNode.setFlag(lc, FunctionNode.IS_ANONYMOUS);
}
final int arity = parameters.size();
- final boolean strict = functionNode.isStrictMode();
+ final boolean strict = functionNode.isStrict();
if (arity > 1) {
final HashSet<String> parametersSet = new HashSet<>(arity);
@@ -2615,39 +2355,37 @@ loop:
final IdentNode parameter = parameters.get(i);
String parameterName = parameter.getName();
- if (ARGUMENTS.tag().equals(parameterName)) {
- functionNode.setDefinesArguments();
+ if (ARGUMENTS.symbolName().equals(parameterName)) {
+ functionNode = functionNode.setFlag(lc, FunctionNode.DEFINES_ARGUMENTS);
}
if (parametersSet.contains(parameterName)) {
// redefinition of parameter name
if (strict) {
- error(AbstractParser.message("strict.param.redefinition", parameterName), parameter.getToken());
- } else {
- // rename in non-strict mode
- parameterName = functionNode.uniqueName(parameterName);
- final long parameterToken = parameter.getToken();
- parameters.set(i, new IdentNode(source, parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName)));
+ throw error(AbstractParser.message("strict.param.redefinition", parameterName), parameter.getToken());
}
+ // rename in non-strict mode
+ parameterName = functionNode.uniqueName(parameterName);
+ final long parameterToken = parameter.getToken();
+ parameters.set(i, new IdentNode(source, parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName)));
}
parametersSet.add(parameterName);
}
} else if (arity == 1) {
- if (ARGUMENTS.tag().equals(parameters.get(0).getName())) {
- functionNode.setDefinesArguments();
+ if (ARGUMENTS.symbolName().equals(parameters.get(0).getName())) {
+ functionNode = functionNode.setFlag(lc, FunctionNode.DEFINES_ARGUMENTS);
}
}
if (isStatement) {
- final VarNode varNode = new VarNode(source, functionToken, finish, name, functionNode, true);
- if(topLevel) {
+ final VarNode varNode = new VarNode(source, functionToken, finish, name, functionNode, VarNode.IS_STATEMENT);
+ if (topLevel) {
functionDeclarations.add(lineNumber);
functionDeclarations.add(varNode);
} else {
- final Block block = getBlock();
- block.addStatement(lineNumber);
- block.addStatement(varNode);
+ appendStatement(lineNumber);
+ appendStatement(varNode);
}
}
@@ -2701,13 +2439,11 @@ loop:
*/
private FunctionNode functionBody(final long firstToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind) {
FunctionNode functionNode = null;
+ long lastToken = 0L;
try {
// Create a new function block.
- functionNode = newFunctionBlock(ident);
- functionNode.setParameters(parameters);
- functionNode.setKind(kind);
- functionNode.setFirstToken(firstToken);
+ functionNode = newFunctionNode(firstToken, ident, parameters, kind);
// Nashorn extension: expression closures
if (!env._no_syntax_extensions && type != LBRACE) {
@@ -2720,14 +2456,12 @@ loop:
// just expression as function body
final Node expr = expression();
-
+ assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode);
// create a return statement - this creates code in itself and does not need to be
// wrapped into an ExecuteNode
- final ReturnNode returnNode = new ReturnNode(source, expr.getToken(), finish, expr, null);
-
- // add the return statement
- functionNode.addStatement(returnNode);
- functionNode.setLastToken(token);
+ final ReturnNode returnNode = new ReturnNode(source, expr.getToken(), finish, expr);
+ appendStatement(returnNode);
+ lastToken = token;
functionNode.setFinish(Token.descPosition(token) + Token.descLength(token));
} else {
@@ -2738,23 +2472,35 @@ loop:
functionDeclarations = new ArrayList<>();
try {
sourceElements();
- functionNode.prependStatements(functionDeclarations);
+ addFunctionDeclarations(functionNode);
} finally {
functionDeclarations = prevFunctionDecls;
}
- functionNode.setLastToken(token);
+ lastToken = token;
expect(RBRACE);
functionNode.setFinish(finish);
}
} finally {
- restoreBlock(functionNode);
+ functionNode = restoreFunctionNode(functionNode, lastToken);
}
-
return functionNode;
}
+ private void addFunctionDeclarations(final FunctionNode functionNode) {
+ assert lc.peek() == lc.getFunctionBody(functionNode);
+ VarNode lastDecl = null;
+ for (int i = functionDeclarations.size() - 1; i >= 0; i--) {
+ Node decl = functionDeclarations.get(i);
+ if (lastDecl == null && decl instanceof VarNode) {
+ decl = lastDecl = ((VarNode)decl).setFlag(VarNode.IS_LAST_FUNCTION_DECLARATION);
+ lc.setFlag(functionNode, FunctionNode.HAS_FUNCTION_DECLARATIONS);
+ }
+ prependStatement(decl);
+ }
+ }
+
private RuntimeNode referenceError(final Node lhs, final Node rhs) {
final ArrayList<Node> args = new ArrayList<>();
args.add(lhs);
@@ -2764,9 +2510,7 @@ loop:
args.add(rhs);
}
args.add(LiteralNode.newInstance(source, lhs.getToken(), lhs.getFinish(), lhs.toString()));
- final RuntimeNode runtimeNode = new RuntimeNode(source, lhs.getToken(),
- lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args);
- return runtimeNode;
+ return new RuntimeNode(source, lhs.getToken(), lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args);
}
/*
@@ -2815,19 +2559,7 @@ loop:
case BIT_NOT:
case NOT:
next();
-
final Node expr = unaryExpression();
-
- /*
- // Not sure if "delete <ident>" is a compile-time error or a
- // runtime error in strict mode.
-
- if (isStrictMode) {
- if (unaryTokenType == DELETE && expr instanceof IdentNode) {
- error(message("strict.cant.delete.ident", ((IdentNode)expr).getName()), expr.getToken());
- }
- }
- */
return new UnaryNode(source, unaryToken, expr);
case INCPREFIX:
@@ -2890,7 +2622,7 @@ loop:
}
if (expression == null) {
- error(AbstractParser.message("expected.operand", type.getNameOrType()));
+ throw error(AbstractParser.message("expected.operand", type.getNameOrType()));
}
return expression;
@@ -2992,6 +2724,7 @@ loop:
// Include commas in expression parsing.
return expression(unaryExpression(), COMMARIGHT.getPrecedence(), false);
}
+
private Node expression(final Node exprLhs, final int minPrecedence, final boolean noIn) {
// Get the precedence of the next operator.
int precedence = type.getPrecedence();
@@ -3087,11 +2820,26 @@ loop:
return "[JavaScript Parsing]";
}
- private Block getBlock() {
- return lexicalContext.getCurrentBlock();
+ private static void markEval(final LexicalContext lc) {
+ final Iterator<FunctionNode> iter = lc.getFunctions();
+ boolean flaggedCurrentFn = false;
+ while (iter.hasNext()) {
+ final FunctionNode fn = iter.next();
+ if (!flaggedCurrentFn) {
+ lc.setFlag(fn, FunctionNode.HAS_EVAL);
+ flaggedCurrentFn = true;
+ } else {
+ lc.setFlag(fn, FunctionNode.HAS_NESTED_EVAL);
+ }
+ lc.setFlag(lc.getFunctionBody(fn), Block.NEEDS_SCOPE);
+ }
+ }
+
+ private void prependStatement(final Node statement) {
+ lc.prependStatement(statement);
}
- private FunctionNode getFunction() {
- return lexicalContext.getCurrentFunction();
+ private void appendStatement(final Node statement) {
+ lc.appendStatement(statement);
}
}