/* * 03/21/2010 * * Copyright (C) 2010 Robert Futrell * robert_futrell at users.sourceforge.net * http://fifesoft.com/rsyntaxtextarea * * This library is distributed under a modified BSD license. See the included * RSTALanguageSupport.License.txt file for details. */ package org.fife.rsta.ac.java.rjc.ast; import java.util.ArrayList; import java.util.List; import org.fife.rsta.ac.java.rjc.lang.Modifiers; import org.fife.rsta.ac.java.rjc.lang.Type; import org.fife.rsta.ac.java.rjc.lexer.Offset; import org.fife.rsta.ac.java.rjc.lexer.TokenTypes; /** * A block of code in curly braces in a class.<p> * * This class implements the <code>Member</code> interface because a block * can be a member (say, a static block in a class declaration), but usually * it's not actually a <code>Member</code>, but something else, e.g. the body * of a method, or the content of an <code>if</code>-statement, etc. * * @author Robert Futrell * @version 1.0 */ public class CodeBlock extends AbstractMember { /** * The name of all <code>CodeBlock</code>s. */ public static final String NAME = "{...}"; private CodeBlock parent; private List children; private List localVars; private boolean isStatic; public CodeBlock(boolean isStatic, Offset startOffs) { super(NAME, startOffs); this.isStatic = isStatic; } public void add(CodeBlock child) { if (children==null) { children = new ArrayList(); } children.add(child); child.setParent(this); } public void addLocalVariable(LocalVariable localVar) { if (localVars==null) { localVars = new ArrayList(); } localVars.add(localVar); } public boolean containsOffset(int offs) { // Do endOffset first since we'll often iterate from first CodeBlock // to last, so checking it first should be faster. return getNameEndOffset()>=offs && getNameStartOffset()<=offs; } public CodeBlock getChildBlock(int index) { return (CodeBlock)children.get(index); } public int getChildBlockCount() { return children==null ? 0 : children.size(); } /** * Returns the deepest code block nested under this one (or this one * itself) containing a given offset. * * @param offs The offset to look for. * @return The deepest-nested code block containing the offset, or * <code>null</code> if this code block and none of its children * contain the offset. */ public CodeBlock getDeepestCodeBlockContaining(int offs) { if (!containsOffset(offs)) { return null; } for (int i=0; i<getChildBlockCount(); i++) { CodeBlock child = getChildBlock(i); if (child.containsOffset(offs)) { return child.getDeepestCodeBlockContaining(offs); } } return this; } public String getDocComment() { // TODO: Can static blocks have doc comments? return null; } public LocalVariable getLocalVar(int index) { return (LocalVariable)localVars.get(index); } public int getLocalVarCount() { return localVars==null ? 0 : localVars.size(); } /** * Returns all local variables declared before a given offset, both in * this code block and in all parent blocks. * * @param offs The offset. * @return The {@link LocalVariable}s, or an empty list of none were * declared before the offset. */ public List getLocalVarsBefore(int offs) { List vars = new ArrayList(); if (localVars!=null) { for (int i=0; i<getLocalVarCount(); i++) { LocalVariable localVar = getLocalVar(i); if (localVar.getNameStartOffset()<offs) { vars.add(localVar); } else { break; } } } if (parent!=null) { vars.addAll(parent.getLocalVarsBefore(offs)); } return vars; } public Modifiers getModifiers() { Modifiers modifiers = new Modifiers(); if (isStatic) { modifiers.addModifier(TokenTypes.KEYWORD_STATIC); } return modifiers; } public CodeBlock getParent() { return parent; } /** * Returns <code>null</code>, since blocks don't have types. * * @return <code>null</code> always. */ public Type getType() { return null; } public boolean isDeprecated() { return false; } /** * Returns whether this block is a static block (in a class declaration). * * @return Whether this is a static code block. */ public boolean isStatic() { return isStatic; } public void setParent(CodeBlock parent) { this.parent = parent; } }