package polyglot.ext.jl.ast;
import java.util.*;
import polyglot.ast.*;
import polyglot.main.Report;
import polyglot.types.*;
import polyglot.util.*;
import polyglot.visit.*;
import polyglot.main.Options;
/**
* A <code>FieldDecl</code> is an immutable representation of the declaration
* of a field of a class.
*/
public class FieldDecl_c extends Term_c implements FieldDecl {
protected Flags flags;
protected TypeNode type;
protected String name;
protected Expr init;
protected FieldInstance fi;
protected InitializerInstance ii;
public FieldDecl_c(Position pos, Flags flags, TypeNode type,
String name, Expr init)
{
super(pos);
this.flags = flags;
this.type = type;
this.name = name;
this.init = init;
}
/** Get the initializer instance of the initializer. */
public InitializerInstance initializerInstance() {
return ii;
}
/** Set the initializer instance of the initializer. */
public FieldDecl initializerInstance(InitializerInstance ii) {
FieldDecl_c n = (FieldDecl_c) copy();
n.ii = ii;
return n;
}
/** Get the type of the declaration. */
public Type declType() {
return type.type();
}
/** Get the flags of the declaration. */
public Flags flags() {
return flags;
}
/** Set the flags of the declaration. */
public FieldDecl flags(Flags flags) {
FieldDecl_c n = (FieldDecl_c) copy();
n.flags = flags;
return n;
}
/** Get the type node of the declaration. */
public TypeNode type() {
return type;
}
/** Set the type of the declaration. */
public FieldDecl type(TypeNode type) {
FieldDecl_c n = (FieldDecl_c) copy();
n.type = type;
return n;
}
/** Get the name of the declaration. */
public String name() {
return name;
}
/** Set the name of the declaration. */
public FieldDecl name(String name) {
FieldDecl_c n = (FieldDecl_c) copy();
n.name = name;
return n;
}
/** Get the initializer of the declaration. */
public Expr init() {
return init;
}
/** Set the initializer of the declaration. */
public FieldDecl init(Expr init) {
FieldDecl_c n = (FieldDecl_c) copy();
n.init = init;
return n;
}
/** Set the field instance of the declaration. */
public FieldDecl fieldInstance(FieldInstance fi) {
FieldDecl_c n = (FieldDecl_c) copy();
n.fi = fi;
return n;
}
/** Get the field instance of the declaration. */
public FieldInstance fieldInstance() {
return fi;
}
/** Reconstruct the declaration. */
protected FieldDecl_c reconstruct(TypeNode type, Expr init) {
if (this.type != type || this.init != init) {
FieldDecl_c n = (FieldDecl_c) copy();
n.type = type;
n.init = init;
return n;
}
return this;
}
/** Visit the children of the declaration. */
public Node visitChildren(NodeVisitor v) {
TypeNode type = (TypeNode) visitChild(this.type, v);
Expr init = (Expr) visitChild(this.init, v);
return reconstruct(type, init);
}
public NodeVisitor buildTypesEnter(TypeBuilder tb) throws SemanticException {
return tb.pushCode();
}
public Node buildTypes(TypeBuilder tb) throws SemanticException {
TypeSystem ts = tb.typeSystem();
FieldDecl n;
if (init != null) {
ClassType ct = tb.currentClass();
Flags f = (flags.isStatic()) ? Flags.STATIC : Flags.NONE;
InitializerInstance ii = ts.initializerInstance(init.position(),
ct, f);
n = initializerInstance(ii);
}
else {
n = this;
}
FieldInstance fi = ts.fieldInstance(n.position(), ts.Object(),
Flags.NONE,
ts.unknownType(position()),
n.name());
return n.fieldInstance(fi);
}
/** Build type objects for the declaration. */
public NodeVisitor disambiguateEnter(AmbiguityRemover ar)
throws SemanticException
{
if (ar.kind() == AmbiguityRemover.SUPER) {
return ar.bypassChildren(this);
}
else if (ar.kind() == AmbiguityRemover.SIGNATURES) {
if (init != null) {
return ar.bypass(init);
}
}
return ar;
}
public Node disambiguate(AmbiguityRemover ar) throws SemanticException {
if (ar.kind() == AmbiguityRemover.SIGNATURES) {
Context c = ar.context();
TypeSystem ts = ar.typeSystem();
ParsedClassType ct = c.currentClassScope();
Flags f = flags;
if (ct.flags().isInterface()) {
f = f.Public().Static().Final();
}
FieldInstance fi = ts.fieldInstance(position(), ct, f,
declType(), name);
return flags(f).fieldInstance(fi);
}
if (ar.kind() == AmbiguityRemover.ALL) {
checkFieldInstanceConstant();
}
return this;
}
protected void checkFieldInstanceConstant() {
FieldInstance fi = this.fi;
if (init != null && fi.flags().isFinal() && init.isConstant()) {
Object value = init.constantValue();
fi.setConstantValue(value);
}
}
public NodeVisitor addMembersEnter(AddMemberVisitor am) {
ParsedClassType ct = am.context().currentClassScope();
FieldInstance fi = this.fi;
if (fi == null) {
throw new InternalCompilerError("null field instance");
}
if (Report.should_report(Report.types, 5))
Report.report(5, "adding " + fi + " to " + ct);
ct.addField(fi);
return am.bypassChildren(this);
}
public Context enterScope(Context c) {
if (ii != null) {
return c.pushCode(ii);
}
return c;
}
/** Type check the declaration. */
public Node typeCheck(TypeChecker tc) throws SemanticException {
TypeSystem ts = tc.typeSystem();
checkFieldInstanceConstant();
try {
ts.checkFieldFlags(flags);
}
catch (SemanticException e) {
throw new SemanticException(e.getMessage(), position());
}
if (tc.context().currentClass().flags().isInterface()) {
if (flags.isProtected() || flags.isPrivate()) {
throw new SemanticException("Interface members must be public.",
position());
}
}
if (init != null) {
if (init instanceof ArrayInit) {
((ArrayInit) init).typeCheckElements(type.type());
}
else {
boolean intConversion = false;
if (! ts.isImplicitCastValid(init.type(), type.type()) &&
! ts.equals(init.type(), type.type()) &&
! ts.numericConversionValid(type.type(),
init.constantValue())) {
throw new SemanticException("The type of the variable " +
"initializer \"" + init.type() +
"\" does not match that of " +
"the declaration \"" +
type.type() + "\".",
init.position());
}
}
}
// check that inner classes do not declare static fields, unless they
// are compile-time constants
if (flags().isStatic() &&
fieldInstance().container().toClass().isInnerClass()) {
// it's a static field in an inner class.
if (!flags().isFinal() || init == null || !init.isConstant()) {
throw new SemanticException("Inner classes cannot declare " +
"static fields, unless they are compile-time " +
"constant fields.", this.position());
}
}
return this;
}
public Node exceptionCheck(ExceptionChecker ec) throws SemanticException {
TypeSystem ts = ec.typeSystem();
SubtypeSet s = (SubtypeSet) ec.throwsSet();
for (Iterator i = s.iterator(); i.hasNext(); ) {
Type t = (Type) i.next();
if (! t.isUncheckedException()) {
ec.throwsSet().clear();
throw new SemanticException(
"A field initializer may not throw a "
+ t + ".", position());
}
}
ec.throwsSet().clear();
return super.exceptionCheck(ec);
}
public Type childExpectedType(Expr child, AscriptionVisitor av) {
if (child == init) {
TypeSystem ts = av.typeSystem();
// If the RHS is an integral constant, we can relax the expected
// type to the type of the constant.
if (ts.numericConversionValid(type.type(), child.constantValue())) {
return child.type();
}
else {
return type.type();
}
}
return child.type();
}
/**
* Return the first (sub)term performed when evaluating this
* term.
*/
public Term entry() {
return init != null ? init.entry() : this;
}
/**
* Visit this term in evaluation order.
*/
public List acceptCFG(CFGBuilder v, List succs) {
if (init != null) {
v.visitCFG(init, this);
}
return succs;
}
public String toString() {
return flags.translate() + type + " " + name +
(init != null ? " = " + init : "");
}
public void prettyPrint(CodeWriter w, PrettyPrinter tr) {
boolean isInterface = fi != null && fi.container() != null &&
fi.container().toClass().flags().isInterface();
Flags f = flags;
if (isInterface) {
f = f.clearPublic();
f = f.clearStatic();
f = f.clearFinal();
}
w.write(f.translate());
print(type, w, tr);
w.write(" ");
w.write(name);
if (init != null) {
w.write(" =");
w.allowBreak(2, " ");
print(init, w, tr);
}
w.write(";");
}
public void dump(CodeWriter w) {
super.dump(w);
if (fi != null) {
w.allowBreak(4, " ");
w.begin(0);
w.write("(instance " + fi + ")");
w.end();
}
w.allowBreak(4, " ");
w.begin(0);
w.write("(name " + name + ")");
w.end();
}
}