001: package gnu.expr;
002:
003: import gnu.bytecode.*;
004:
005: /**
006: * Abstract class for expressions that add local variable bindings.
007: * @author Per Bothner
008: */
009:
010: public abstract class ScopeExp extends Expression {
011: Declaration decls;
012: Declaration last;
013:
014: private Scope scope;
015:
016: public Declaration firstDecl() {
017: return decls;
018: }
019:
020: public Scope getVarScope() {
021: Scope sc = scope;
022: if (sc == null)
023: scope = sc = new Scope();
024: return sc;
025: }
026:
027: /** Clear bytecode resources for the ScopeExp.
028: * This potentially allows Kawa to generate code for the same (inlined,
029: * shared) ScopeExp multiple times - though we're not making use of that yet.
030: */
031: public void popScope(CodeAttr code) {
032: for (Declaration decl = firstDecl(); decl != null; decl = decl
033: .nextDecl())
034: decl.var = null;
035: code.popScope();
036: scope = null;
037: }
038:
039: public void add(Declaration decl) {
040: if (last == null)
041: decls = decl;
042: else
043: last.next = decl;
044: last = decl;
045: decl.context = this ;
046: }
047:
048: /** Add a Declaration at a specified position.
049: */
050: public void add(Declaration prev, Declaration decl) {
051: if (prev == null) { // Put first
052: decl.next = decls;
053: decls = decl;
054: } else {
055: decl.next = prev.next;
056: prev.next = decl;
057: }
058: if (last == prev)
059: last = decl;
060: decl.context = this ;
061: }
062:
063: /** Replace the <code>prev.next</code> by <code>newDecl</code>.
064: * If <code>prev==null</code>, replace the first decl. */
065: public void replaceFollowing(Declaration prev, Declaration newDecl) {
066: Declaration oldDecl;
067: if (prev == null) {
068: oldDecl = decls;
069: decls = newDecl;
070: } else {
071: oldDecl = prev.next;
072: prev.next = newDecl;
073: }
074: newDecl.next = oldDecl.next;
075: if (last == oldDecl)
076: last = newDecl;
077: oldDecl.next = null;
078: newDecl.context = this ;
079: }
080:
081: public void remove(Declaration decl) {
082: Declaration prev = null;
083: for (Declaration cur = firstDecl(); cur != null; cur = cur
084: .nextDecl()) {
085: if (cur == decl) {
086: remove(prev, decl);
087: return;
088: }
089: prev = cur;
090: }
091: }
092:
093: public void remove(Declaration prev, Declaration decl) {
094: if (prev == null)
095: decls = decl.next;
096: else
097: prev.next = decl.next;
098: if (last == decl)
099: last = prev;
100: }
101:
102: public ScopeExp() {
103: }
104:
105: /** The statically enclosing binding contour. */
106: public ScopeExp outer;
107:
108: public LambdaExp currentLambda() {
109: ScopeExp exp = this ;
110: for (;; exp = exp.outer) {
111: if (exp == null)
112: return null;
113: if (exp instanceof LambdaExp)
114: return (LambdaExp) exp;
115: }
116: }
117:
118: public ModuleExp currentModule() {
119: ScopeExp exp = this ;
120: for (;; exp = exp.outer) {
121: if (exp == null)
122: return null;
123: if (exp instanceof ModuleExp)
124: return (ModuleExp) exp;
125: }
126: }
127:
128: /**
129: * Find a Declaration by name.
130: * @param sym the (interned) name of the Declaration sought
131: * @return the matching Declaration, if found; otherwise null
132: */
133: public Declaration lookup(Object sym) {
134: if (sym != null) {
135: for (Declaration decl = firstDecl(); decl != null; decl = decl
136: .nextDecl()) {
137: if (sym.equals(decl.symbol))
138: return decl;
139: }
140: }
141: return null;
142: }
143:
144: public Declaration lookup(Object sym, Language language,
145: int namespace) {
146: for (Declaration decl = firstDecl(); decl != null; decl = decl
147: .nextDecl()) {
148: if (sym.equals(decl.symbol)
149: && language.hasNamespace(decl, namespace))
150: return decl;
151: }
152: return null;
153: }
154:
155: /** Lookup a declaration, create a non-defining declaration if needed. */
156: public Declaration getNoDefine(Object name) {
157: Declaration decl = lookup(name);
158: if (decl == null) {
159: decl = addDeclaration(name);
160: decl.flags |= Declaration.NOT_DEFINING
161: | Declaration.IS_UNKNOWN;
162: }
163: return decl;
164: }
165:
166: /** Add a new Declaration, with a message if there is an existing one. */
167: public Declaration getDefine(Object name, char severity,
168: Compilation parser) {
169: Declaration decl = lookup(name);
170: if (decl == null)
171: decl = addDeclaration(name);
172: else if ((decl.flags & (Declaration.NOT_DEFINING | Declaration.IS_UNKNOWN)) != 0)
173: decl.flags &= ~(Declaration.NOT_DEFINING | Declaration.IS_UNKNOWN);
174: else {
175: Declaration newDecl = addDeclaration(name);
176: duplicateDeclarationError(decl, newDecl, parser);
177: decl = newDecl;
178: }
179: return decl;
180: }
181:
182: public static void duplicateDeclarationError(Declaration oldDecl,
183: Declaration newDecl, Compilation comp) {
184: comp.error('e', newDecl, "duplicate declaration of '", "'");
185: comp.error('e', oldDecl,
186: "(this is the previous declaration of '", "')");
187: }
188:
189: /**
190: * Create a new declaration in the current Scope.
191: * @param name name (interned) to give to the new Declaration.
192: */
193: public final Declaration addDeclaration(Object name) {
194: Declaration decl = new Declaration(name);
195: add(decl);
196: return decl;
197: }
198:
199: /**
200: * Create a new declaration in the current Scope.
201: * @param name name (interned) to give to the new Declaration.
202: * @param type type of the new Declaration.
203: */
204: public final Declaration addDeclaration(Object name, Type type) {
205: Declaration decl = new Declaration(name, type);
206: add(decl);
207: return decl;
208: }
209:
210: /**
211: * Add a Declaration to the current Scope.
212: */
213: public final void addDeclaration(Declaration decl) {
214: add(decl); // FIXME just use add
215: }
216:
217: public int countDecls() {
218: int n = 0;
219: for (Declaration decl = firstDecl(); decl != null; decl = decl
220: .nextDecl())
221: n++;
222: return n;
223: }
224:
225: public static int nesting(ScopeExp sc) {
226: int n = 0;
227: while (sc != null) {
228: sc = sc.outer;
229: n++;
230: }
231: return n;
232: }
233:
234: /** Size of evalFrame to allocate in interpreter. */
235: protected int frameSize;
236:
237: /** Calculate offset and frameSize needed by interpreter. */
238: protected void setIndexes() {
239: int i = 0;
240: for (Declaration decl = firstDecl(); decl != null; decl = decl
241: .nextDecl()) {
242: decl.evalIndex = i++;
243: }
244: frameSize = i;
245: }
246:
247: protected Expression walk(ExpWalker walker) {
248: return walker.walkScopeExp(this );
249: }
250:
251: public String toString() {
252: return getClass().getName() + "#" + id;
253: }
254:
255: static int counter;
256: /** Unique id number, to ease print-outs and debugging. */
257: public int id = ++counter;
258: }
|