package LBJ2.IR; import java.util.HashSet; import LBJ2.Pass; import LBJ2.frontend.TokenValue; /** * This class represents a scalar variable. * * @author Nick Rizzolo **/ public class Name extends Expression { /** * (¬ø) These strings appeared with dots between them to form * the name in the source. **/ public String[] name; /** * The number of matched brackets appearing after a single identifier; * supports variable declarations. **/ public int dimensions; /** * Takes a fully specified name (eg java.lang.String) as input. * * @param n A fully specified name. **/ public Name(String n) { this(n, -1, -1); } /** * Takes a fully specified name (eg java.lang.String) as input. * * @param n A fully specified name. **/ public Name(String n, int line, int byteOffset) { super(line, byteOffset); name = n.split("\\."); dimensions = 0; } /** * Should only be called by the <code>clone()</code> method. * * @param n The value of the <code>name</code> variable. **/ protected Name(String[] n) { this(n, -1, -1); } /** * Should only be called by the <code>clone()</code> method. * * @param n The value of the <code>name</code> variable. **/ protected Name(String[] n, int line, int byteOffset) { super(line, byteOffset); name = (String[]) n.clone(); dimensions = 0; } /** * Parser's constructor. * * @param token The parser's token for the identifier. **/ public Name(TokenValue token) { super(token.line, token.byteOffset); name = new String[1]; name[0] = token.toString(); dimensions = 0; } /** * Parser's constructor. * * @param n A name that needs another identifier added to it. * @param token The parser's token for the identifier. **/ public Name(Name n, TokenValue token) { super(n.line, n.byteOffset); name = new String[n.name.length + 1]; for (int i = 0; i < n.name.length; ++i) name[i] = n.name[i]; name[n.name.length] = token.toString(); } /** * Returns the length of the <code>name</code> array. * * @return The length of the <code>name</code> array. **/ public int length() { return name.length; } /** * Returns a new <code>Name</code> object that is the same as this * <code>Name</code> object, except the last identifier has been removed. **/ public Name cutLast() { String[] n = new String[name.length - 1]; for (int i = 0; i < n.length; ++i) n[i] = name[i]; return new Name(n); } /** * Returns a set of <code>Argument</code>s storing the name and type of * each variable that is a subexpression of this expression. This method * cannot be run before <code>SemanticAnalysis</code> runs. **/ public HashSet getVariableTypes() { HashSet result = new HashSet(); Type type = null; if (name.length == 1) type = typeCache; else type = symbolTable.get(name[0]); if (type != null && (type instanceof ArrayType || type instanceof ReferenceType || type instanceof PrimitiveType)) result.add(new Argument(type, name[0])); return result; } /** * Returns a set of <code>Argument</code>s storing the name and type of * each variable that is a subexpression of this expression. This method * cannot be run before <code>SemanticAnalysis</code> runs. * * @param b Flag set if this name is the name of an invoked method. **/ public HashSet getVariableTypes(boolean b) { if (!b || name.length > 1) return getVariableTypes(); return new HashSet(); } /** * Determines if there are any quantified variables in this expression. * This method cannot be run before <code>SemanticAnalysis</code> runs. **/ public boolean containsQuantifiedVariable() { HashSet types = getVariableTypes(); if (types.size() == 0) return false; return ((Argument) types.iterator().next()).getType().quantifierArgumentType; } /** * Determines if there are any quantified variables in this expression. * This method cannot be run before <code>SemanticAnalysis</code> runs. * * @param b Flag set if this name is the name of an invoked method. **/ public boolean containsQuantifiedVariable(boolean b) { if (!b || name.length > 1) return containsQuantifiedVariable(); return false; } /** * Returns a hash code value for java hash structures. * * @return A hash code for this object. **/ public int hashCode() { int code = 0; for (int i = 0; i < name.length; ++i) code += name[i].hashCode(); return code; } /** * Indicates whether some other object is "equal to" this one. * * @return <code>true</code> iff this object is the same as the argument. **/ public boolean equals(Object o) { if (!(o instanceof Name)) return false; Name n = (Name) o; if (n.name.length != name.length) return false; for (int i = 0; i < name.length; ++i) if (!name[i].equals(n.name[i])) return false; return true; } /** * Returns an iterator used to successively access the children of this * node. * * @return An iterator used to successively access the children of this * node. **/ public ASTNodeIterator iterator() { return new ASTNodeIterator(0); } /** * Creates a new object with the same primitive data, and recursively * creates new member data objects as well. * * @return The clone node. **/ public Object clone() { return new Name(name, line, byteOffset); } /** * Ensures that the correct <code>run()</code> method is called for this * type of node. * * @param pass The pass whose <code>run()</code> method should be called. **/ public void runPass(Pass pass) { pass.run(this); } /** * Writes a string representation of this <code>ASTNode</code> to the * specified buffer. The representation written is parsable by the LBJ2 * compiler, but not very readable. * * @param buffer The buffer to write to. **/ public void write(StringBuffer buffer) { if (parenthesized) buffer.append("("); if (name.length > 0) { buffer.append(name[0]); for (int i = 1; i < name.length; ++i) { buffer.append("."); buffer.append(name[i]); } } if (parenthesized) buffer.append(")"); } }