/******************************************************************************* * Copyright (c) 2012 Google, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Google, Inc. - initial API and implementation *******************************************************************************/ package com.windowtester.codegen.assembly.block; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Set; import com.windowtester.codegen.assembly.unit.CodeUnit; import com.windowtester.codegen.assembly.unit.VarUnit; /** * A base class for basic code units. */ public class CodeBlock extends CodeUnit { /** List of child blocks */ private List _blocks; /** The parent code unit (might be null) */ private CodeUnit _parent; /** Set of locally defined variables */ private Set _locals; /** A list of exceptions caught in this block, if non-null, the block * wraps a try-catch */ private List _catches; /** The body of this block */ private String _body; /** * Create an instance. */ public CodeBlock() { } /** * Create an instance. * @param body */ public CodeBlock(String body) { _body = body; } /** * Create an instance. * @param body */ public CodeBlock(StringBuffer body) { this(body.toString()); } public void setBody(String body) { _body = body; } /** * @return the list of child blocks */ private List getBlocks() { if (_blocks == null) _blocks = new LinkedList(); return _blocks; } /** * @return the set of locally defined variables */ public Set getLocals() { if (_locals == null) _locals = new HashSet(); return _locals; } /** * @return the list of catch clauses that close this block (null if there are none) * TODO: maybe this should be pushed into a TryCatchBlock? */ public List getCatches() { if (_catches == null) _catches = new ArrayList(); return _catches; } /** * Get the children of this block. Note that this list is immutable, * to add entries, see the addChild*(..) and removeChild(..) methods. * @return the list of children */ public List getChildren() { return Collections.unmodifiableList(getBlocks()); } /** * Remove this block from the list of children. * @param child */ public void removeChild(CodeBlock child) { getBlocks().remove(child); } /** * Adds a block to the end of this block's list of children * @param block */ public void addChild(CodeBlock block){ block._parent = this; getBlocks().add(block); } /** * Add this block before the given block in the child list. If the block * to precede is not in the list, the block is inserted at the start of the list. * @param toAdd * @param toPrecede */ public void addChildBefore(CodeBlock toAdd, CodeBlock toPrecede) { toAdd._parent = this; int index = getBlocks().indexOf(toPrecede); if (index == -1) index = 0; getBlocks().add(index, toAdd); } /** * Add this block before the given block in the child list.If the block * to sucede is not in the list, the block is inserted at the end of the list. * @param toAdd * @param toAdd * @param toSucede */ public void addChildAfter(CodeBlock toAdd, CodeBlock toSucede) { toAdd._parent = this; int index = 0; //if it's not at the beginning, look for the right index if (toSucede != null) index = getBlocks().indexOf(toSucede); if (index == -1) index = getBlocks().size()-1; getBlocks().add(index, toAdd); } /** * @return this block's immediate parent */ public CodeUnit getParent() { return _parent; } /** * Checks to see if a given id is in scope. * @param id - the id to check * @return true if the given name is in scope * TODO: needs to walk up the chain of blocks... */ public boolean isIdentifierInScope(String id) { Set localVars = getLocals(); for (Iterator iter = localVars.iterator(); iter.hasNext();) { VarUnit local = (VarUnit) iter.next(); if (local.getName().equals(id)) return true; } //for now, very naive: doesn't check fields... //TODO: might consider an "owner" field to identify the type that owns the block to make //field lookup easier... return false; } /* (non-Javadoc) * @see java.lang.Object#toString() */ public String toString() { StringBuffer sb = new StringBuffer(); sb.append(_body == null ? "" : _body); for (Iterator iter = getBlocks().iterator(); iter.hasNext();) { CodeBlock element = (CodeBlock) iter.next(); sb.append(element); } return sb.toString(); } /** * Ad a local variable definition to this block. * @param name */ public void addLocal(VarUnit var) { getLocals().add(var); } }