package polyglot.ext.jl.ast; import polyglot.ast.*; import polyglot.main.Options; import polyglot.types.*; import polyglot.visit.*; import polyglot.util.*; import java.util.*; /** * A <code>LocalDecl</code> is an immutable representation of the declaration * of a local variable. */ public class LocalDecl_c extends Stmt_c implements LocalDecl { protected Flags flags; protected TypeNode type; protected String name; protected Expr init; protected LocalInstance li; public LocalDecl_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 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 LocalDecl flags(Flags flags) { LocalDecl_c n = (LocalDecl_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 LocalDecl type(TypeNode type) { if (type == this.type) return this; LocalDecl_c n = (LocalDecl_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 LocalDecl name(String name) { if (name.equals(this.name)) return this; LocalDecl_c n = (LocalDecl_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 LocalDecl init(Expr init) { if (init == this.init) return this; LocalDecl_c n = (LocalDecl_c) copy(); n.init = init; return n; } /** Set the local instance of the declaration. */ public LocalDecl localInstance(LocalInstance li) { if (li == this.li) return this; LocalDecl_c n = (LocalDecl_c) copy(); n.li = li; return n; } /** Get the local instance of the declaration. */ public LocalInstance localInstance() { return li; } /** Reconstruct the declaration. */ protected LocalDecl_c reconstruct(TypeNode type, Expr init) { if (this.type != type || this.init != init) { LocalDecl_c n = (LocalDecl_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); } /** * Add the declaration of the variable as we enter the scope of the * intializer */ public Context enterScope(Node child, Context c) { if (child == init) { c.addVariable(li); } return super.enterScope(child, c); } public void addDecls(Context c) { // Add the declaration of the variable in case we haven't already done // so in enterScope, when visiting the initializer. c.addVariable(li); } public Node buildTypes(TypeBuilder tb) throws SemanticException { LocalDecl_c n = (LocalDecl_c) super.buildTypes(tb); TypeSystem ts = tb.typeSystem(); LocalInstance li = ts.localInstance(position(), Flags.NONE, ts.unknownType(position()), name()); return n.localInstance(li); } public Node disambiguate(AmbiguityRemover ar) throws SemanticException { TypeSystem ts = ar.typeSystem(); LocalInstance li = ts.localInstance(position(), flags(), declType(), name()); return localInstance(li); } /** * Override superclass behaviour to check if the variable is multiply * defined. */ public NodeVisitor typeCheckEnter(TypeChecker tc) throws SemanticException { // Check if the variable is multiply defined. // we do it in type check enter, instead of type check since // we add the declaration before we enter the scope of the // initializer. Context c = tc.context(); LocalInstance outerLocal = null; try { outerLocal = c.findLocal(li.name()); } catch (SemanticException e) { // not found, so not multiply defined } if (outerLocal != null && c.isLocal(li.name())) { throw new SemanticException( "Local variable \"" + name + "\" multiply defined. " + "Previous definition at " + outerLocal.position() + ".", position()); } return super.typeCheckEnter(tc); } /** Type check the declaration. */ public Node typeCheck(TypeChecker tc) throws SemanticException { TypeSystem ts = tc.typeSystem(); LocalInstance li = this.li; if (li.flags().isFinal() && init() != null && init().isConstant()) { Object value = init().constantValue(); li = (LocalInstance) li.constantValue(value); } try { ts.checkLocalFlags(flags); } catch (SemanticException e) { throw new SemanticException(e.getMessage(), position()); } if (init != null) { if (init instanceof ArrayInit) { ((ArrayInit) init).typeCheckElements(type.type()); } else { 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()); } } } return localInstance(li); } 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(); } public String toString() { return flags.translate() + type + " " + name + (init != null ? " = " + init : "") + ";"; } public void prettyPrint(CodeWriter w, PrettyPrinter tr) { boolean printSemi = tr.appendSemicolon(true); boolean printType = tr.printType(true); w.write(flags.translate()); if (printType) { print(type, w, tr); w.write(" "); } w.write(name); if (init != null) { w.write(" ="); w.allowBreak(2, " "); print(init, w, tr); } if (printSemi) { w.write(";"); } tr.printType(printType); tr.appendSemicolon(printSemi); } public void dump(CodeWriter w) { super.dump(w); if (li != null) { w.allowBreak(4, " "); w.begin(0); w.write("(instance " + li + ")"); w.end(); } w.allowBreak(4, " "); w.begin(0); w.write("(name " + name + ")"); w.end(); } public Term entry() { if (init() != null) { return init().entry(); } return this; } public List acceptCFG(CFGBuilder v, List succs) { if (init() != null) { v.visitCFG(init(), this); } return succs; } }