/* * 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.ast; import java.util.ArrayList; import java.util.Collections; import java.util.List; import polyglot.types.*; import polyglot.util.CodeWriter; import polyglot.util.InternalCompilerError; import polyglot.util.Position; import polyglot.visit.*; import x10.errors.Errors; /** * A <code>LocalDecl</code> is an immutable representation of the declaration * of a local variable. */ public abstract class LocalDecl_c extends Stmt_c implements LocalDecl { protected FlagsNode flags; protected TypeNode type; protected Id name; protected Expr init; protected LocalDef li; public LocalDecl_c(Position pos, FlagsNode flags, TypeNode type, Id name, Expr init) { super(pos); assert(flags != null && type != null && name != null); // init may be null this.flags = flags; this.type = type; this.name = name; this.init = init; } public List<Def> defs() { return Collections.<Def>singletonList(li); } /** Get the type of the declaration. */ public Type declType() { return type.type(); } /** Get the flags of the declaration. */ public FlagsNode flags() { return flags; } /** Set the flags of the declaration. */ public LocalDecl flags(FlagsNode 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 Id name() { return name; } /** Set the name of the declaration. */ public LocalDecl name(Id name) { 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 localDef(LocalDef li) { if (li == this.li) return this; LocalDecl_c n = (LocalDecl_c) copy(); assert li != null; n.li = li; return n; } /** Get the local instance of the declaration. */ public LocalDef localDef() { return li; } public VarDef varDef() { return li; } /** Reconstruct the declaration. */ protected LocalDecl_c reconstruct(FlagsNode flags, TypeNode type, Id name, Expr init) { if (this.flags != flags || this.type != type || this.name != name || this.init != init) { LocalDecl_c n = (LocalDecl_c) copy(); n.flags = flags; n.type = type; n.name = name; 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); FlagsNode flags = (FlagsNode) visitChild(this.flags, v); Id name = (Id) visitChild(this.name, v); Expr init = (Expr) visitChild(this.init, v); return reconstruct(flags, type, name, init); } 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.asInstance()); } public Node buildTypes(TypeBuilder tb) { LocalDecl_c n = (LocalDecl_c) super.buildTypes(tb); TypeSystem ts = tb.typeSystem(); LocalDef li = ts.localDef(position(), flags().flags(), type.typeRef(), name.id()); return n.localDef(li); } /** * Override superclass behavior to check if the variable is multiply * defined. */ public NodeVisitor typeCheckEnter(TypeChecker tc) { // 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())) { Errors.issue(tc.job(), new SemanticException("Local variable \"" + name + "\" multiply defined. Previous definition at " + outerLocal.position() + ".", position())); } return super.typeCheckEnter(tc); } /** Type check the declaration. */ public abstract Node typeCheck(ContextVisitor tc); public Node checkConstants(ContextVisitor tc) { if (init == null || ! init.isConstant() || ! li.flags().isFinal()) { li.setNotConstant(); } else { li.setConstantValue(init.constantValue()); } return this; } public abstract String toString(); public abstract void prettyPrint(CodeWriter w, PrettyPrinter tr); public void dump(CodeWriter w) { super.dump(w); if (li != null) { w.allowBreak(4, " "); w.begin(0); w.write("(instance " + li + ")"); w.end(); } } public Term firstChild() { return type(); } public <S> List<S> acceptCFG(CFGBuilder v, List<S> succs) { if (init() != null) { v.visitCFG(type(), init(), ENTRY); v.visitCFG(init(), this, EXIT); } else { v.visitCFG(type(), this, EXIT); } return succs; } }