1 /* 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.nashorn.internal.ir; 27 28 import java.util.ArrayDeque; 29 import java.util.ArrayList; 30 import java.util.Deque; 31 import java.util.List; 32 33 /** 34 * This is a subclass of lexical context used for filling 35 * blocks (and function nodes) with statements. When popping 36 * a block from the lexical context, any statements that have 37 * been generated in it are committed to the block. This saves 38 * unnecessary object mutations and lexical context replacement 39 */ 40 public class BlockLexicalContext extends LexicalContext { 41 /** statement stack, each block on the lexical context maintains one of these, which is 42 * committed to the block on pop */ 43 private final Deque<List<Statement>> sstack = new ArrayDeque<>(); 44 45 /** Last non debug statement emitted in this context */ 46 protected Statement lastStatement; 47 48 @Override 49 public <T extends LexicalContextNode> T push(final T node) { 50 final T pushed = super.push(node); 51 if (node instanceof Block) { 52 sstack.push(new ArrayList<Statement>()); 53 } 54 return pushed; 55 } 56 57 /** 58 * Get the statement list from the stack, possibly filtered 59 * @return statement list 60 */ 61 protected List<Statement> popStatements() { 62 return sstack.pop(); 63 } 64 65 /** 66 * Override this method to perform some additional processing on the block after its statements have been set. By 67 * default does nothing and returns the original block. 68 * @param block the block to operate on 69 * @return a modified block. 70 */ 71 protected Block afterSetStatements(final Block block) { 72 return block; 73 } 74 75 @SuppressWarnings("unchecked") 76 @Override 77 public <T extends Node> T pop(final T node) { 78 T expected = node; 79 if (node instanceof Block) { 80 final List<Statement> newStatements = popStatements(); 81 expected = (T)((Block)node).setStatements(this, newStatements); 82 expected = (T)afterSetStatements((Block)expected); 83 if (!sstack.isEmpty()) { 84 lastStatement = lastStatement(sstack.peek()); 85 } 86 } 87 return super.pop(expected); 88 } 89 90 /** 91 * Append a statement to the block being generated 92 * @param statement statement to add 93 */ 94 public void appendStatement(final Statement statement) { 95 assert statement != null; 96 sstack.peek().add(statement); 97 lastStatement = statement; 98 } 99 100 /** 101 * Prepend a statement to the block being generated 102 * @param statement statement to prepend 103 * @return the prepended statement 104 */ 105 public Node prependStatement(final Statement statement) { 106 assert statement != null; 107 sstack.peek().add(0, statement); 108 return statement; 109 } 110 111 /** 112 * Prepend a list of statement to the block being generated 113 * @param statements a list of statements to prepend 114 */ 115 public void prependStatements(final List<Statement> statements) { 116 assert statements != null; 117 sstack.peek().addAll(0, statements); 118 } 119 120 121 /** 122 * Get the last statement that was emitted into a block 123 * @return the last statement emitted 124 */ 125 public Statement getLastStatement() { 126 return lastStatement; 127 } 128 129 private static Statement lastStatement(final List<Statement> statements) { 130 final int s = statements.size(); 131 return s == 0 ? null : statements.get(s - 1); 132 } 133 }