package files; import java.util.List; import util.StringUtils; /** * Represents a require statement made from a source file. * * A require statement is an import statement that specifies explicitly which * source file is being depended upon. See {@link driver.RequiresParser} for * more information about require statements. * * There are three flavors of requires: Regular requires import a class * (possibly nested) from a source file. Static requires import a class member * from a source file (the member can be a method or a nested class, although a * static require for a nested class is similar to a regular require for the * same class). Macro requires import a macro from a macro source file. * * For static and macro requires, the member or macro name (respectively) can * also be a star ("*"), meaning all members or macros should be imported. * * For regular import, the class chain may consist of a single star ("*"), * meaning that all top-level classes in the file are required. * * The class chain may also end with a star, meaning that all the static inner * classes of the preceding class chain are required. */ public class Require { /****************************************************************************/ private final RelativeSourcePath path; /****************************************************************************/ private final List<String> classes; /****************************************************************************/ private final String member; /***************************************************************************** * $path is a relative path to the file containing the required items. * * $classes is a list of class names forming the path to an imported * class (a nested class if classe.size() > 1). null for a macro require. * * $member is the name of the imported member in a static require, or * the name of macro in a macro require. null for a regular require. */ public Require(RelativeSourcePath path, List<String> classes, String member) { classes = classes != null && classes.isEmpty() ? null : classes; member = member != null && member .isEmpty() ? null : member; this.path = path; this.classes = classes; this.member = member; } /****************************************************************************/ public List<String> classes() { return classes; } /****************************************************************************/ public String member() { return member; } /****************************************************************************/ public String macro() { return member; } /****************************************************************************/ public RelativeSourcePath relativePath() { return path; } /****************************************************************************/ public boolean isStatic() { return member != null && classes != null; } /****************************************************************************/ public boolean isMacro() { return member != null && classes == null; } /****************************************************************************/ public boolean isRegular() { return member == null && classes != null; } /***************************************************************************** * Only for static requires: indicate if all static members in the file * are required by this require statement. */ public boolean requiresAllMembers() { return member.equals("*"); } /***************************************************************************** * Only for regular requires: indicates if all top-level classes in the file * are required by this require statement. */ public boolean requiresAllClasses() { return classes.get(0).equals("*"); } /***************************************************************************** * A string containing the class names returned by classes(), joined by * dots. */ public String classChain() { if (classes == null) { return ""; } return StringUtils.join(classes, "."); } /***************************************************************************** * Returns a String presenting the require as an import statement, if applicable. * If not, returns the empty string. */ public String importString() { if (isMacro()) { return ""; } String middle = path.pkg().name() + "." + classChain(); return isStatic() ? "import static " + middle + "." + member + ";" : "import " + middle + ";"; } /****************************************************************************/ @Override public String toString() { String keyword = isMacro() ? "macro " : isStatic() ? "static " : ""; String pkgString = path.pkgString(); String separator = isStatic() ? "." : ""; String memberString = member != null ? member : ""; return keyword + pkgString + ":" + classChain() + separator + memberString; } /****************************************************************************/ @Override public boolean equals(Object o) { if (!(o instanceof Require)) { return false; } Require other = (Require) o; boolean cEqual = classes != null ? classes.equals(other.classes) : other.classes == null; boolean mEqual = member != null ? member.equals(other.member) : other.member == null; return path.equals(other.path) && cEqual && mEqual; } /****************************************************************************/ @Override public int hashCode() { int cCode = classes == null ? 0 : classes.hashCode(); int mCode = member == null ? 0 : member .hashCode(); return path.hashCode() ^ cCode ^ mCode; } }