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: Scope scope;
015:
016: public final Declaration firstDecl() {
017: return decls;
018: }
019:
020: public void add(Declaration decl) {
021: if (last == null)
022: decls = decl;
023: else
024: last.next = decl;
025: last = decl;
026: decl.context = this ;
027: }
028:
029: /** Add a Declaration at a specified position.
030: */
031: public void add(Declaration prev, Declaration decl) {
032: if (prev == null) { // Put first
033: decl.next = decls;
034: decls = decl;
035: } else {
036: decl.next = prev.next;
037: prev.next = decl;
038: }
039: if (last == prev)
040: last = decl;
041: decl.context = this ;
042: }
043:
044: public void remove(Declaration decl) {
045: Declaration prev = null;
046: for (Declaration cur = firstDecl(); cur != null; cur = cur
047: .nextDecl()) {
048: if (cur == decl) {
049: remove(prev, decl);
050: return;
051: }
052: prev = decl;
053: }
054: }
055:
056: public void remove(Declaration prev, Declaration decl) {
057: if (prev == null)
058: decls = decl.next;
059: else
060: prev.next = decl.next;
061: if (last == decl)
062: last = prev;
063: }
064:
065: public ScopeExp() {
066: scope = new Scope();
067: }
068:
069: /** The statically enclosing binding contour. */
070: public ScopeExp outer;
071:
072: public LambdaExp currentLambda() {
073: ScopeExp exp = this ;
074: for (;; exp = exp.outer) {
075: if (exp == null)
076: return null;
077: if (exp instanceof LambdaExp)
078: return (LambdaExp) exp;
079: }
080: }
081:
082: public ClassExp currentClass() {
083: ScopeExp exp = this ;
084: for (;; exp = exp.outer) {
085: if (exp == null)
086: return null;
087: if (exp instanceof ClassExp)
088: return (ClassExp) exp;
089: }
090: }
091:
092: public ModuleExp currentModule() {
093: ScopeExp exp = this ;
094: for (;; exp = exp.outer) {
095: if (exp == null)
096: return null;
097: if (exp instanceof ModuleExp)
098: return (ModuleExp) exp;
099: }
100: }
101:
102: /**
103: * Find a Declaration by name.
104: * @param sym the (interned) name of the Declaration sought
105: * @return the matching Declaration, if found; otherwise null
106: */
107: public Declaration lookup(String sym) {
108: for (Declaration decl = firstDecl(); decl != null; decl = decl
109: .nextDecl()) {
110: if (decl.name == sym)
111: return decl;
112: }
113: return null;
114: }
115:
116: public Declaration lookup(String sym, Interpreter interp,
117: int namespace) {
118: for (Declaration decl = firstDecl(); decl != null; decl = decl
119: .nextDecl()) {
120: if (decl.name == sym
121: && (interp.getNamespaceOf(decl) & namespace) != 0)
122: return decl;
123: }
124: return null;
125: }
126:
127: /** Lookup a declaration, create a non-defining declaration if needed. */
128: public Declaration getNoDefine(String name) {
129: Declaration decl = lookup(name);
130: if (decl == null) {
131: decl = addDeclaration(name);
132: decl.setFlag(Declaration.NOT_DEFINING);
133: }
134: return decl;
135: }
136:
137: /** Add a new Declaration, with a message if there is an existing one. */
138: public Declaration getDefine(String name, char severity,
139: Parser parser) {
140: Declaration decl = lookup(name);
141: if (decl == null)
142: decl = addDeclaration(name);
143: else if (decl.getFlag(Declaration.NOT_DEFINING))
144: decl.setFlag(false, Declaration.NOT_DEFINING);
145: else if (decl.getFlag(Declaration.IS_UNKNOWN))
146: decl.setFlag(false, Declaration.IS_UNKNOWN);
147: else {
148: StringBuffer sbuf = new StringBuffer(200);
149: sbuf.append("duplicate definition for '");
150: sbuf.append(name);
151: int oldLine = decl.getLine();
152: if (oldLine <= 0)
153: sbuf.append('\'');
154: else {
155: sbuf.append("\' (overrides ");
156: String oldFile = decl.getFile();
157: if (oldFile == null || oldFile.equals(parser.getFile()))
158: sbuf.append("line ");
159: else {
160: sbuf.append(oldFile);
161: sbuf.append(':');
162: }
163: sbuf.append(oldLine);
164: int oldColumn = decl.getColumn();
165: if (oldColumn > 0) {
166: sbuf.append(':');
167: sbuf.append(oldColumn);
168: }
169: sbuf.append(')');
170: }
171: parser.error(severity, sbuf.toString());
172: decl = addDeclaration(name);
173: }
174: return decl;
175: }
176:
177: /**
178: * Create a new declaration in the current Scope.
179: * @param name name (interned) to give to the new Declaration.
180: */
181: public final Declaration addDeclaration(String name) {
182: Declaration decl = new Declaration(name);
183: addDeclaration(decl);
184: return decl;
185: }
186:
187: /**
188: * Create a new declaration in the current Scope.
189: * @param name name (interned) to give to the new Declaration.
190: * @param type type of the new Declaration.
191: */
192: public final Declaration addDeclaration(String name, Type type) {
193: Declaration decl = new Declaration(name);
194: addDeclaration(decl);
195: decl.setType(type);
196: return decl;
197: }
198:
199: /**
200: * Add a Declaration to the current Scope.
201: */
202: public final void addDeclaration(Declaration decl) {
203: add(decl); // FIXME just use add
204: }
205:
206: public int countDecls() {
207: int n = 0;
208: for (Declaration decl = firstDecl(); decl != null; decl = decl
209: .nextDecl())
210: n++;
211: return n;
212: }
213:
214: protected Expression walk(ExpWalker walker) {
215: return walker.walkScopeExp(this);
216: }
217: }
|