/*
* This file is part of the X10 project (http://x10-lang.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* This file was originally derived from the Polyglot extensible compiler framework.
*
* (C) Copyright 2000-2007 Polyglot project group, Cornell University
* (C) Copyright IBM Corporation 2007-2012.
*/
package polyglot.types;
import java.io.Serializable;
import java.util.*;
/**
* <code>Flags</code> is an immutable set of class, method, or field modifiers.
* We represent package scope as the absence of private, public and protected
* scope modifiers.
*/
public class Flags implements Serializable
{
private static final long serialVersionUID = -539580723506705467L;
protected Set<String> flags;
public static final Flags NONE = new Flags();
public static final Flags PUBLIC = createFlag("public", null);
public static final Flags PRIVATE = createFlag("private", null);
public static final Flags PROTECTED = createFlag("protected", null);
public static final Flags STATIC = createFlag("static", null);
public static final Flags FINAL = createFlag("final", null);
public static final Flags TRANSIENT = createFlag("transient", null);
public static final Flags NATIVE = createFlag("native", null);
public static final Flags INTERFACE = createFlag("interface", null);
public static final Flags ABSTRACT = createFlag("abstract", null);
public static final Flags JAVA_FLAGS = PUBLIC.Private().Protected().Static().Final().Transient().Native().Interface().Abstract();
public static final Flags REFERENCE = createFlag("reference", null);
public static final Flags ATOMIC = createFlag("atomic", null);
public static final Flags PURE = createFlag("pure", null);
public static final Flags MUTABLE = createFlag("mutable", null);
public static final Flags PROPERTY = createFlag("property", null);
public static final Flags STRUCT = createFlag("struct", null);
public static final Flags CLOCKED = createFlag("clocked", null);
/** All access flags. */
protected static final Flags ACCESS_FLAGS = PUBLIC.set(PRIVATE).set(PROTECTED);
/**
* Return a new Flags object with a new name. Should be called only once
* per name.
*
* @param name the name of the new flag
* @param after the flags after which this flag should be printed;
* Flags.NONE to print before all other flags, null
* if we should print at the end.
*/
private static Flags createFlag(String name, Flags after) {
return new Flags(name);
}
/**
* Effects: returns a new accessflags object with no accessflags set.
*/
protected Flags() {
this.flags = new TreeSet<String>();
}
protected Flags(String name) {
this();
flags.add(name);
}
public Set<String> flags() {
return this.flags;
}
/**
* Create new flags with the flags in <code>other</code> also set.
*/
public Flags set(Flags other) {
Flags f = new Flags();
f.flags.addAll(this.flags);
f.flags.addAll(other.flags);
return f;
}
/**
* Create new flags with the flags in <code>other</code> cleared.
*/
public Flags clear(Flags other) {
Flags f = new Flags();
f.flags.addAll(this.flags);
f.flags.removeAll(other.flags);
return f;
}
/**
* Create new flags with only flags in <code>other</code> set.
*/
public Flags retain(Flags other) {
Flags f = new Flags();
f.flags.addAll(this.flags);
f.flags.retainAll(other.flags);
return f;
}
public Flags retainJava() {
return retain(JAVA_FLAGS);
}
/**
* Check if <i>any</i> flags in <code>other</code> are set.
*/
public boolean intersects(Flags other) {
for (String name : this.flags) {
if (other.flags.contains(name)) {
return true;
}
}
return false;
}
/**
* Check if <i>all</i> flags in <code>other</code> are set.
*/
public boolean contains(Flags other) {
return this.flags.containsAll(other.flags);
}
/**
* Return a copy of this <code>this</code> with the <code>public</code>
* flag set.
*/
public Flags Public() {
return set(PUBLIC);
}
/**
* Return a copy of this <code>this</code> with the <code>public</code>
* flag clear.
*/
public Flags clearPublic() {
return clear(PUBLIC);
}
/**
* Return true if <code>this</code> has the <code>public</code> flag set.
*/
public boolean isPublic() {
return contains(PUBLIC);
}
/**
* Return a copy of this <code>this</code> with the <code>private</code>
* flag set.
*/
public Flags Private() {
return set(PRIVATE);
}
/**
* Return a copy of this <code>this</code> with the <code>private</code>
* flag clear.
*/
public Flags clearPrivate() {
return clear(PRIVATE);
}
/**
* Return true if <code>this</code> has the <code>private</code> flag set.
*/
public boolean isPrivate() {
return contains(PRIVATE);
}
/**
* Return a copy of this <code>this</code> with the <code>protected</code>
* flag set.
*/
public Flags Protected() {
return set(PROTECTED);
}
/**
* Return a copy of this <code>this</code> with the <code>protected</code>
* flag clear.
*/
public Flags clearProtected() {
return clear(PROTECTED);
}
/**
* Return true if <code>this</code> has the <code>protected</code> flag set.
*/
public boolean isProtected() {
return contains(PROTECTED);
}
/**
* Return a copy of this <code>this</code> with no access flags
* (<code>public</code>, <code>private</code>, <code>protected</code>) set.
*/
public Flags Package() {
return clear(ACCESS_FLAGS);
}
/**
* Return true if <code>this</code> has the no access flags
* (<code>public</code>, <code>private</code>, <code>protected</code>) set.
*/
public boolean isPackage() {
return ! intersects(ACCESS_FLAGS);
}
/**
* Return a copy of this <code>this</code> with the <code>static</code>
* flag set.
*/
public Flags Static() {
return set(STATIC);
}
/**
* Return a copy of this <code>this</code> with the <code>static</code>
* flag clear.
*/
public Flags clearStatic() {
return clear(STATIC);
}
/**
* Return true if <code>this</code> has the <code>static</code> flag set.
*/
public boolean isStatic() {
return contains(STATIC);
}
/**
* Return a copy of this <code>this</code> with the <code>final</code>
* flag set.
*/
public Flags Final() {
return set(FINAL);
}
/**
* Return a copy of this <code>this</code> with the <code>final</code>
* flag clear.
*/
public Flags clearFinal() {
return clear(FINAL);
}
/**
* Return true if <code>this</code> has the <code>final</code> flag set.
*/
public boolean isFinal() {
return contains(FINAL);
}
/**
* Return a copy of this <code>this</code> with the <code>transient</code>
* flag set.
*/
public Flags Transient() {
return set(TRANSIENT);
}
/**
* Return a copy of this <code>this</code> with the <code>transient</code>
* flag clear.
*/
public Flags clearTransient() {
return clear(TRANSIENT);
}
/**
* Return true if <code>this</code> has the <code>transient</code> flag set.
*/
public boolean isTransient() {
return contains(TRANSIENT);
}
/**
* Return a copy of this <code>this</code> with the <code>native</code>
* flag set.
*/
public Flags Native() {
return set(NATIVE);
}
/**
* Return a copy of this <code>this</code> with the <code>native</code>
* flag clear.
*/
public Flags clearNative() {
return clear(NATIVE);
}
/**
* Return true if <code>this</code> has the <code>native</code> flag set.
*/
public boolean isNative() {
return contains(NATIVE);
}
/**
* Return a copy of this <code>this</code> with the <code>interface</code>
* flag set.
*/
public Flags Interface() {
return set(INTERFACE);
}
/**
* Return a copy of this <code>this</code> with the <code>interface</code>
* flag clear.
*/
public Flags clearInterface() {
return clear(INTERFACE);
}
/**
* Return true if <code>this</code> has the <code>interface</code> flag set.
*/
public boolean isInterface() {
return contains(INTERFACE);
}
/**
* Return a copy of this <code>this</code> with the <code>abstract</code>
* flag set.
*/
public Flags Abstract() {
return set(ABSTRACT);
}
/**
* Return a copy of this <code>this</code> with the <code>abstract</code>
* flag clear.
*/
public Flags clearAbstract() {
return clear(ABSTRACT);
}
/**
* Return true if <code>this</code> has the <code>abstract</code> flag set.
*/
public boolean isAbstract() {
return contains(ABSTRACT);
}
/**
* Return a copy of this <code>this</code> with the <code>atomic</code> flag
* set.
*/
public Flags Atomic() {
return set(ATOMIC);
}
/**
* Return a copy of this <code>this</code> with the <code>atomic</code> flag
* clear.
*/
public Flags clearAtomic() {
return clear(ATOMIC);
}
/**
* Return true if <code>this</code> has the <code>atomic</code> flag set.
*/
public boolean isAtomic() {
return contains(ATOMIC);
}
/**
* Return a copy of this <code>this</code> with the <code>pure</code> flag
* set.
*/
public Flags Pure() {
return set(PURE);
}
/**
* Return a copy of this <code>this</code> with the <code>pure</code> flag
* clear.
*/
public Flags clearPure() {
return clear(PURE);
}
/**
* Return true if <code>this</code> has the <code>pure</code> flag set.
*/
public boolean isPure() {
return contains(PURE);
}
/**
* Return a copy of this <code>this</code> with the <code>struct</code> flag
* set.
*/
public Flags Struct() {
return set(STRUCT);
}
/**
* Return a copy of this <code>this</code> with the <code>struct</code> flag
* clear.
*/
public Flags clearStruct() {
return clear(STRUCT);
}
/**
* Return true if <code>this</code> has the <code>struct</code> flag set.
*/
public boolean isStruct() {
return contains(STRUCT);
}
/**
* Return a copy of this <code>this</code> with the <code>property</code>
* flag set.
*/
public Flags Property() {
return set(PROPERTY);
}
/**
* Return a copy of this <code>this</code> with the <code>property</code>
* flag clear.
*/
public Flags clearProperty() {
return clear(PROPERTY);
}
/**
* Return true if <code>this</code> has the <code>property</code> flag set.
*/
public boolean isProperty() {
return contains(PROPERTY);
}
/**
* Return a copy of this <code>this</code> with the <code>pinned</code>
* flag set.
*/
public Flags Clocked() {
return set(CLOCKED);
}
/**
* Return a copy of this <code>this</code> with the <code>pinned</code>
* flag clear.
*/
public Flags clearClocked() {
return clear(CLOCKED);
}
/**
* Return true if <code>this</code> has the <code>pinned</code> flag
* set.
*/
public boolean isClocked() {
return contains(CLOCKED);
}
/**
* Return true if <code>this</code> has more restrictive access flags than
* <code>f</code>.
*/
public boolean moreRestrictiveThan(Flags f) {
if (isPrivate() && (f.isProtected() || f.isPackage() || f.isPublic())) {
return true;
}
if (isPackage() && (f.isProtected() || f.isPublic())) {
return true;
}
if (isProtected() && f.isPublic()) {
return true;
}
if (!isProperty() && f.isProperty())
return true;
return false;
}
public String toString() {
StringBuffer sb = new StringBuffer();
for (Iterator<String> i = this.flags.iterator(); i.hasNext();) {
String s = i.next();
sb.append(s);
if (i.hasNext())
sb.append(" ");
}
return sb.toString();
}
/**
* Return "" if no flags set, or toString() + " " if some flags are set.
*/
public String translateJava() {
return retainJava().translate();
}
public String translate() {
StringBuffer sb = new StringBuffer();
for (String s : this.flags) {
sb.append(s);
sb.append(" ");
}
return sb.toString();
}
public int hashCode() {
return flags.hashCode();
}
public boolean equals(Object o) {
return o instanceof Flags && flags.equals(((Flags) o).flags);
}
public String prettyPrint() {
return translate();
}
public boolean hasAllAnnotationsOf(Flags f) {
boolean result = true;
// Report.report(1, "Flags: " + this + ".hasAllAnnotationsOf(" + f +
// ")? " + result);
return result;
}
}