@Override public <T extends LexicalContextNode> T pop(final T node) { final T popped = super.pop(node); if (isWithBoundary(node)) { dynamicScopeCount--; assert dynamicScopeCount >= 0; } else if (node instanceof FunctionNode) { if (((FunctionNode)node).inDynamicContext()) { dynamicScopeCount--; assert dynamicScopeCount >= 0; } assert splitNodes.peek() == 0; splitNodes.pop(); } return popped; }
private Map<Symbol, LvarType> getBreakTargetTypes(final BreakableNode target) { // Remove symbols defined in the the blocks that are being broken out of. Map<Symbol, LvarType> types = localVariableTypes; for(final Iterator<LexicalContextNode> it = lc.getAllNodes(); it.hasNext();) { final LexicalContextNode node = it.next(); if(node instanceof Block) { for(final Symbol symbol: ((Block)node).getSymbols()) { if(localVariableTypes.containsKey(symbol)) { if(types == localVariableTypes) { types = cloneMap(localVariableTypes); } types.remove(symbol); } } } if(node == target) { break; } } return types; }
private Map<Symbol, LvarType> getBreakTargetTypes(final LexicalContextNode target) { // Remove symbols defined in the the blocks that are being broken out of. Map<Symbol, LvarType> types = localVariableTypes; for(final Iterator<LexicalContextNode> it = lc.getAllNodes(); it.hasNext();) { final LexicalContextNode node = it.next(); if(node instanceof Block) { for(final Symbol symbol: ((Block)node).getSymbols()) { if(localVariableTypes.containsKey(symbol)) { if(types == localVariableTypes) { types = cloneMap(localVariableTypes); } types.remove(symbol); } } } if(node == target) { break; } } return types; }
/** * Determines if the symbol has to be a scope symbol. In general terms, it has to be a scope symbol if it can only * be reached from the current block by traversing a function node, a split node, or a with node. * @param symbol the symbol checked for needing to be a scope symbol * @return true if the symbol has to be a scope symbol. */ private boolean symbolNeedsToBeScope(final Symbol symbol) { if (symbol.isThis() || symbol.isInternal()) { return false; } final FunctionNode func = lc.getCurrentFunction(); if ( func.allVarsInScope() || (!symbol.isBlockScoped() && func.isProgram())) { return true; } boolean previousWasBlock = false; for (final Iterator<LexicalContextNode> it = lc.getAllNodes(); it.hasNext();) { final LexicalContextNode node = it.next(); if (node instanceof FunctionNode || isSplitArray(node)) { // We reached the function boundary or a splitting boundary without seeing a definition for the symbol. // It needs to be in scope. return true; } else if (node instanceof WithNode) { if (previousWasBlock) { // We reached a WithNode; the symbol must be scoped. Note that if the WithNode was not immediately // preceded by a block, this means we're currently processing its expression, not its body, // therefore it doesn't count. return true; } previousWasBlock = false; } else if (node instanceof Block) { if (((Block)node).getExistingSymbol(symbol.getName()) == symbol) { // We reached the block that defines the symbol without reaching either the function boundary, or a // WithNode. The symbol need not be scoped. return false; } previousWasBlock = true; } else { previousWasBlock = false; } } throw new AssertionError(); }
private static boolean isSplitArray(final LexicalContextNode expr) { if(!(expr instanceof ArrayLiteralNode)) { return false; } final List<ArrayUnit> units = ((ArrayLiteralNode)expr).getUnits(); return !(units == null || units.isEmpty()); }
@Override public <T extends LexicalContextNode> T push(final T node) { if (isWithBoundary(node)) { dynamicScopeCount++; } else if (node instanceof FunctionNode) { if (((FunctionNode)node).inDynamicContext()) { dynamicScopeCount++; } splitNodes.push(0); } return super.push(node); }
/** * Determines if the symbol has to be a scope symbol. In general terms, it has to be a scope symbol if it can only * be reached from the current block by traversing a function node, a split node, or a with node. * @param symbol the symbol checked for needing to be a scope symbol * @return true if the symbol has to be a scope symbol. */ private boolean symbolNeedsToBeScope(final Symbol symbol) { if (symbol.isThis() || symbol.isInternal()) { return false; } final FunctionNode func = lc.getCurrentFunction(); if ( func.allVarsInScope() || (!symbol.isBlockScoped() && func.isProgram())) { return true; } boolean previousWasBlock = false; for (final Iterator<LexicalContextNode> it = lc.getAllNodes(); it.hasNext();) { final LexicalContextNode node = it.next(); if (node instanceof FunctionNode || isSplitLiteral(node)) { // We reached the function boundary or a splitting boundary without seeing a definition for the symbol. // It needs to be in scope. return true; } else if (node instanceof WithNode) { if (previousWasBlock) { // We reached a WithNode; the symbol must be scoped. Note that if the WithNode was not immediately // preceded by a block, this means we're currently processing its expression, not its body, // therefore it doesn't count. return true; } previousWasBlock = false; } else if (node instanceof Block) { if (((Block)node).getExistingSymbol(symbol.getName()) == symbol) { // We reached the block that defines the symbol without reaching either the function boundary, or a // WithNode. The symbol need not be scoped. return false; } previousWasBlock = true; } else { previousWasBlock = false; } } throw new AssertionError(); }
/** * Determines if the symbol has to be a scope symbol. In general terms, it * has to be a scope symbol if it can only be reached from the current block * by traversing a function node, a split node, or a with node. * * @param symbol the symbol checked for needing to be a scope symbol * @return true if the symbol has to be a scope symbol. */ private boolean symbolNeedsToBeScope(final Symbol symbol) { if (symbol.isThis() || symbol.isInternal()) { return false; } final FunctionNode func = lc.getCurrentFunction(); if (func.allVarsInScope() || (!symbol.isBlockScoped() && func.isProgram())) { return true; } boolean previousWasBlock = false; for (final Iterator<LexicalContextNode> it = lc.getAllNodes(); it.hasNext();) { final LexicalContextNode node = it.next(); if (node instanceof FunctionNode || isSplitLiteral(node)) { // We reached the function boundary or a splitting boundary without seeing a definition for the symbol. // It needs to be in scope. return true; } else if (node instanceof WithNode) { if (previousWasBlock) { // We reached a WithNode; the symbol must be scoped. Note that if the WithNode was not immediately // preceded by a block, this means we're currently processing its expression, not its body, // therefore it doesn't count. return true; } previousWasBlock = false; } else if (node instanceof Block) { if (((Block) node).getExistingSymbol(symbol.getName()) == symbol) { // We reached the block that defines the symbol without reaching either the function boundary, or a // WithNode. The symbol need not be scoped. return false; } previousWasBlock = true; } else { previousWasBlock = false; } } throw new AssertionError(); }
private boolean symbolNeedsToBeScope(Symbol symbol) { if (symbol.isThis() || symbol.isInternal()) { return false; } boolean previousWasBlock = false; for (final Iterator<LexicalContextNode> it = lc.getAllNodes(); it.hasNext();) { final LexicalContextNode node = it.next(); if (node instanceof FunctionNode) { // We reached the function boundary without seeing a definition for the symbol - it needs to be in // scope. return true; } else if (node instanceof WithNode) { if (previousWasBlock) { // We reached a WithNode; the symbol must be scoped. Note that if the WithNode was not immediately // preceded by a block, this means we're currently processing its expression, not its body, // therefore it doesn't count. return true; } previousWasBlock = false; } else if (node instanceof Block) { if (((Block)node).getExistingSymbol(symbol.getName()) == symbol) { // We reached the block that defines the symbol without reaching either the function boundary, or a // WithNode. The symbol need not be scoped. return false; } previousWasBlock = true; } else { previousWasBlock = false; } } throw new AssertionError(); }
@Override public <T extends LexicalContextNode> T push(final T node) { if (isDynamicScopeBoundary(node)) { ++dynamicScopeCount; } return super.push(node); }
@Override public <T extends LexicalContextNode> T pop(final T node) { final T popped = super.pop(node); if (isDynamicScopeBoundary(popped)) { --dynamicScopeCount; } if (node instanceof Block) { --nextFreeSlotsSize; } return popped; }
private boolean isDynamicScopeBoundary(final LexicalContextNode node) { if (node instanceof Block) { // Block's immediate parent is a with node. Note we aren't testing for a WithNode, as that'd capture // processing of WithNode.expression too, but it should be unaffected. return !isEmpty() && peek() instanceof WithNode; } else if (node instanceof FunctionNode) { // Function has a direct eval in it (so a top-level "var ..." in the eval code can introduce a new // variable into the function's scope), and it isn't strict (as evals in strict functions get an // isolated scope). return isFunctionDynamicScope((FunctionNode)node); } return false; }
private boolean isWithBoundary(final LexicalContextNode node) { return node instanceof Block && !isEmpty() && peek() instanceof WithNode; }