1 package gnu.expr; 2 import gnu.bytecode.*; 3 4 /** 5 * Abstract class for expressions that add local variable bindings. 6 * @author Per Bothner 7 */ 8 9 public abstract class ScopeExp extends Expression 10 { 11 Declaration decls; 12 Declaration last; 13 14 protected Scope scope; 15 firstDecl()16 public Declaration firstDecl () { return decls; } lastDecl()17 public Declaration lastDecl() { return last; } 18 getVarScope()19 public Scope getVarScope () 20 { 21 Scope sc = scope; 22 if (sc == null) 23 scope = sc = new Scope(); 24 return sc; 25 } 26 27 /** Clear bytecode resources for the ScopeExp. 28 * This potentially allows Kawa to generate code for the same (inlined, 29 * shared) ScopeExp multiple times - though we're not making use of that yet. 30 */ popScope(CodeAttr code)31 public void popScope (CodeAttr code) 32 { 33 for (Declaration decl = firstDecl(); decl != null; decl = decl.nextDecl()) 34 decl.var = null; 35 code.popScope(); 36 scope = null; 37 } 38 add(Declaration decl)39 public void add (Declaration decl) 40 { 41 if (last == null) 42 decls = decl; 43 else 44 last.setNext(decl); 45 last = decl; 46 decl.context = this; 47 } 48 49 /** Add a Declaration at a specified position. 50 */ add(Declaration prev, Declaration decl)51 public void add (Declaration prev, Declaration decl) 52 { 53 if (prev == null) 54 { // Put first 55 decl.setNext(decls); 56 decls = decl; 57 } 58 else 59 { 60 decl.setNext(prev.nextDecl()); 61 prev.setNext(decl); 62 } 63 if (last == prev) 64 last = decl; 65 decl.context = this; 66 } 67 68 /** Replace the <code>prev.next</code> by <code>newDecl</code>. 69 * If <code>prev==null</code>, replace the first decl. */ replaceFollowing(Declaration prev, Declaration newDecl)70 public void replaceFollowing (Declaration prev, Declaration newDecl) 71 { 72 Declaration oldDecl; 73 if (prev == null) 74 { 75 oldDecl = decls; 76 decls = newDecl; 77 } 78 else 79 { 80 oldDecl = prev.nextDecl(); 81 prev.setNext(newDecl); 82 } 83 newDecl.setNext(oldDecl.nextDecl()); 84 if (last == oldDecl) 85 last = newDecl; 86 oldDecl.setNext(null); 87 newDecl.context = this; 88 } 89 remove(Declaration decl)90 public void remove (Declaration decl) 91 { 92 Declaration prev = null; 93 for (Declaration cur = firstDecl(); cur != null; cur = cur.nextDecl()) 94 { 95 if (cur == decl) 96 { 97 remove(prev, decl); 98 return; 99 } 100 prev = cur; 101 } 102 } 103 remove(Declaration prev, Declaration decl)104 public void remove (Declaration prev, Declaration decl) 105 { 106 Declaration next = decl.nextDecl(); 107 if (prev == null) 108 decls = next; 109 else 110 prev.setNext(next); 111 if (last == decl) 112 last = prev; 113 decl.setNext(null); 114 } 115 ScopeExp()116 public ScopeExp () { } 117 118 /** The statically enclosing binding contour. */ 119 private ScopeExp outer; 120 121 /** Return the statically enclosing binding contour. */ getOuter()122 public ScopeExp getOuter() { return outer; } 123 setOuter(ScopeExp outer)124 public void setOuter(ScopeExp outer) { this.outer = outer; } 125 currentLambda()126 public LambdaExp currentLambda () 127 { 128 ScopeExp exp = this; 129 for (;; exp = exp.getOuter()) 130 { 131 if (exp == null) 132 return null; 133 if (exp instanceof LambdaExp) 134 return (LambdaExp) exp; 135 } 136 } 137 138 /** Return the outermost non-module scope, if there is one. */ topLevel()139 public ScopeExp topLevel () 140 { 141 ScopeExp exp = this; 142 for (;; ) 143 { 144 ScopeExp outer = exp.getOuter(); 145 if (outer == null || outer instanceof ModuleExp) 146 return exp; 147 exp = outer; 148 } 149 } 150 currentModule()151 public ModuleExp currentModule () 152 { 153 ScopeExp exp = this; 154 for (;; exp = exp.getOuter()) 155 { 156 if (exp == null) 157 return null; 158 if (exp instanceof ModuleExp) 159 return (ModuleExp) exp; 160 } 161 } 162 163 /** 164 * Find a Declaration by name. 165 * @param sym the (interned) name of the Declaration sought 166 * @return the matching Declaration, if found; otherwise null 167 */ lookup(Object sym)168 public Declaration lookup (Object sym) 169 { 170 if (sym != null) 171 { 172 for (Declaration decl = firstDecl(); 173 decl != null; decl = decl.nextDecl()) 174 { 175 if (sym.equals(decl.symbol)) 176 return decl; 177 } 178 } 179 return null; 180 } 181 lookup(Object sym, Language language, int namespace)182 public Declaration lookup (Object sym, Language language, int namespace) 183 { 184 for (Declaration decl = firstDecl(); 185 decl != null; decl = decl.nextDecl()) 186 { 187 if (sym.equals(decl.symbol) 188 && language.hasNamespace(decl, namespace)) 189 return decl; 190 } 191 return null; 192 } 193 194 /** Lookup a declaration, create a non-defining declaration if needed. */ getNoDefine(Object name)195 public Declaration getNoDefine (Object name) 196 { 197 Declaration decl = lookup(name); 198 if (decl == null) 199 { 200 decl = addDeclaration(name); 201 decl.flags |= Declaration.NOT_DEFINING | Declaration.IS_UNKNOWN; 202 } 203 return decl; 204 } 205 206 /** Add a new Declaration, with a message if there is an existing one. */ getDefine(Object name, Compilation parser)207 public Declaration getDefine (Object name, Compilation parser) 208 { 209 Declaration decl = lookup(name); 210 if (decl == null) 211 decl = addDeclaration(name); 212 else if ((decl.flags & (Declaration.NOT_DEFINING | Declaration.IS_UNKNOWN)) 213 != 0) 214 decl.flags &= ~ (Declaration.NOT_DEFINING|Declaration.IS_UNKNOWN); 215 else 216 { 217 Declaration newDecl = addDeclaration(name); 218 duplicateDeclarationError(decl, newDecl, parser); 219 decl = newDecl; 220 } 221 return decl; 222 } 223 duplicateDeclarationError(Declaration oldDecl, Declaration newDecl, Compilation comp)224 public static void duplicateDeclarationError (Declaration oldDecl, 225 Declaration newDecl, 226 Compilation comp) 227 { 228 comp.error('e', newDecl, "duplicate declaration of '", "'"); 229 comp.error('e', oldDecl, "(this is the previous declaration of '", "')"); 230 } 231 232 /** 233 * Create a new declaration in the current Scope. 234 * @param name name (interned) to give to the new Declaration. 235 */ addDeclaration(Object name)236 public final Declaration addDeclaration (Object name) 237 { 238 Declaration decl = new Declaration (name); 239 add(decl); 240 return decl; 241 } 242 243 /** 244 * Create a new declaration in the current Scope. 245 * @param name name (interned) to give to the new Declaration. 246 * @param type type of the new Declaration. 247 */ addDeclaration(Object name, Type type)248 public final Declaration addDeclaration (Object name, Type type) 249 { 250 Declaration decl = new Declaration (name, type); 251 add(decl); 252 return decl; 253 } 254 255 /** 256 * Add a Declaration to the current Scope. 257 */ addDeclaration(Declaration decl)258 public final void addDeclaration (Declaration decl) 259 { 260 add(decl); // FIXME just use add 261 } 262 countDecls()263 public int countDecls () 264 { 265 int n = 0; 266 for (Declaration decl = firstDecl(); decl != null; decl = decl.nextDecl()) 267 n++; 268 return n; 269 } 270 clearCallList()271 public void clearCallList () 272 { 273 for (Declaration decl = firstDecl(); decl != null; decl = decl.nextDecl()) 274 decl.clearCallList(); 275 } 276 nesting(ScopeExp sc)277 public static int nesting (ScopeExp sc) 278 { 279 int n = 0; 280 while (sc != null) 281 { 282 sc = sc.getOuter(); 283 n++; 284 } 285 return n; 286 } 287 288 /** True if given scope is nesed in this scope, perhaps indirectly. */ nestedIn(ScopeExp outer)289 public boolean nestedIn (ScopeExp outer) 290 { 291 for (ScopeExp sc = this; sc != null; sc = sc.getOuter()) 292 { 293 if (sc == outer) 294 return true; 295 } 296 return false; 297 } 298 /** Size of evalFrame to allocate in interpreter. */ 299 protected int frameSize; 300 301 /** Calculate offset and frameSize needed by interpreter. */ setIndexes()302 protected void setIndexes () 303 { 304 int i = 0; 305 for (Declaration decl = firstDecl(); decl != null; decl = decl.nextDecl()) 306 { 307 decl.evalIndex = i++; 308 } 309 frameSize = i; 310 } 311 visit(ExpVisitor<R,D> visitor, D d)312 protected <R,D> R visit (ExpVisitor<R,D> visitor, D d) 313 { 314 return visitor.visitScopeExp(this, d); 315 } 316 317 /** True if a class is generated for this scope. */ isClassGenerated()318 public final boolean isClassGenerated() { 319 return this instanceof ModuleExp || this instanceof ClassExp; 320 } 321 toString()322 public String toString() { return getClass().getName()+"#"+id; } 323 324 static int counter; 325 /** Unique id number, to ease print-outs and debugging. */ 326 public int id = ++counter; 327 } 328