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