001: /**************************************************************************/
002: /* N I C E */
003: /* A high-level object-oriented research language */
004: /* (c) Daniel Bonniot 2000 */
005: /* */
006: /* This program is free software; you can redistribute it and/or modify */
007: /* it under the terms of the GNU General Public License as published by */
008: /* the Free Software Foundation; either version 2 of the License, or */
009: /* (at your option) any later version. */
010: /* */
011: /**************************************************************************/package bossa.syntax;
012:
013: import java.util.*;
014: import bossa.util.*;
015: import mlsub.typing.TypeSymbol;
016:
017: /**
018: Basic component of the syntax tree.
019: Defines its local scope.
020:
021: @version $Date: 2005/03/11 17:35:52 $
022: @author Daniel Bonniot (d.bonniot@mail.dotcom.fr)
023: */
024: abstract public class Node {
025: static final int global = 1;
026: static final int down = 2;
027: static final int upper = 3;
028: static final int none = 4;
029:
030: Node(int propagate) {
031: this .propagate = propagate;
032: }
033:
034: Node(List /* of Node */children, int propagate) {
035: this (propagate);
036: addChildren(children);
037: }
038:
039: /** child(n) is prefered now */
040: void addChild(Node n) {
041: if (n == null)
042: Internal.error("null child in Node.addChild for node "
043: + this );
044:
045: if (children == null)
046: children = new ArrayList();
047: children.add(n);
048: }
049:
050: final Node child(Node n) {
051: if (n == null)
052: return null;
053:
054: if (children == null)
055: children = new ArrayList();
056: children.add(n);
057: return n;
058: }
059:
060: void removeChild(Node n) {
061: if (children == null || !children.contains(n))
062: Internal.error(n + " is not a child of " + this );
063:
064: children.remove(n);
065: }
066:
067: void removeChildren() {
068: children = null;
069: }
070:
071: /**
072: * Always returns the argument (except an empty list for 'null').
073: * This is just a convenience to be able to write 'this.f = addChildren(f)'.
074: */
075: List addChildren(List c) {
076: if (c == null)
077: return Collections.EMPTY_LIST;
078:
079: for (Iterator i = c.iterator(); i.hasNext();)
080: addChild((Node) i.next());
081:
082: return c;
083: }
084:
085: void addSymbol(/*VarSymbol*/Symbol s) {
086: if (varSymbols == null)
087: varSymbols = new ArrayList();
088: varSymbols.add(s);
089: }
090:
091: void addTypeSymbol(TypeSymbol s) {
092: addTypeMap(s.toString(), s);
093: }
094:
095: void addTypeMap(String name, TypeSymbol symbol) {
096: if (typeMapsNames == null) {
097: typeMapsNames = new ArrayList();
098: typeMapsSymbols = new ArrayList();
099: }
100: typeMapsNames.add(name);
101: typeMapsSymbols.add(symbol);
102: }
103:
104: /**
105: * Scopes shared by all modules.
106: */
107:
108: public static final TypeScope getGlobalTypeScope() {
109: return compilation.globalTypeScope;
110: }
111:
112: public static final bossa.modules.Package getGlobalTypeScopeModule() {
113: return compilation.globalTypeScope.getPackage();
114: }
115:
116: public static mlsub.typing.TypeConstructor globalTypeScopeLookup(
117: String name, Location loc) {
118: return compilation.globalTypeScope.globalLookup(name, loc);
119: }
120:
121: public static bossa.modules.Compilation compilation = null;
122:
123: public static void setPackage(bossa.modules.Package pkg) {
124: // For multiple compilations in the same JVM:
125: // If we are starting a new compilation, reset the global scopes.
126: if (compilation != pkg.getCompilation()) {
127: compilation = pkg.getCompilation();
128: if (compilation.globalTypeScope == null)
129: compilation.globalTypeScope = dispatch
130: .createGlobalTypeScope();
131: }
132: compilation.globalTypeScope.setPackage(pkg);
133: }
134:
135: void buildScope(bossa.modules.Package pkg) {
136: setPackage(pkg);
137: buildScope(null, compilation.globalTypeScope);
138: }
139:
140: /**
141: Sets up the scope, once the outer scope is given.
142: */
143: void buildScope(VarScope outer, TypeScope typeOuter) {
144: //if (this.scope != null)
145: //Internal.error("Scope set twice for " + this + this.getClass());
146:
147: if (this instanceof Definition)
148: outer = ((Definition) this ).module.scope;
149:
150: switch (propagate) {
151: case none:
152: this .scope = outer;
153: this .typeScope = typeOuter;
154: break;
155: case down:
156: this .scope = VarScope.create(outer, varSymbols);
157: this .typeScope = new TypeScope(typeOuter);
158: break;
159:
160: case global:
161: this .scope = outer;
162: this .scope.addSymbols(varSymbols);
163: typeOuter = compilation.globalTypeScope;
164: this .typeScope = typeOuter;
165: break;
166:
167: case upper:
168: if (outer == null)
169: outer = VarScope.create(null);
170: outer.addSymbols(varSymbols);
171: this .scope = outer;
172: if (typeOuter == null)
173: typeOuter = new TypeScope(null);
174: this .typeScope = typeOuter;
175: break;
176:
177: default:
178: Internal.error("Invalid case in Node.buildScope");
179: }
180:
181: if (propagate != none) {
182: try {
183: if (typeMapsNames != null)
184: this .typeScope
185: .addMappings(
186: typeMapsNames,
187: (TypeSymbol[]) typeMapsSymbols
188: .toArray(new TypeSymbol[typeMapsSymbols
189: .size()]));
190: } catch (TypeScope.DuplicateName e) {
191: if (this instanceof Located)
192: User.error(((Located) this ).location(), e
193: .getMessage());
194: else
195: /// XXX This error will not be located.
196: User.error(e);
197: }
198: }
199:
200: // They won't be used anymore
201: // Let's enable the memory to be reclamed
202: varSymbols = null;
203: typeMapsSymbols = null;
204: typeMapsNames = null;
205:
206: // builds the scope of the children
207: if (children != null) {
208: for (Iterator i = children.iterator(); i.hasNext();) {
209: Node d = (Node) i.next();
210: d.buildScope(this .scope, this .typeScope);
211: }
212: }
213: }
214:
215: VarScope getScope() {
216: return scope;
217: }
218:
219: TypeScope getTypeScope() {
220: return typeScope;
221: }
222:
223: /****************************************************************
224: * Scoping resolution
225: ****************************************************************/
226:
227: /** uses the scope to replace identifiers with their meaning */
228: void resolve() {
229: }
230:
231: void doResolve() {
232: if (Debug.resolution)
233: Debug.println("Resolving " + this + " [" + this .getClass()
234: + "]");
235:
236: resolve();
237:
238: // They won't be used anymore
239: // Let's enable the memory to be reclamed
240: scope = null;
241: typeScope = null;
242:
243: if (children != null)
244: for (Iterator i = children.iterator(); i.hasNext();)
245: ((Node) i.next()).doResolve();
246:
247: if (Debug.resolution)
248: Debug.println("Resolved to " + this + " ["
249: + this .getClass() + "]");
250: }
251:
252: /****************************************************************
253: * Type checking
254: ****************************************************************/
255:
256: // The current function should be saved in nodes that need it
257: // during execution of their typecheck method.
258: static/*Function*/Object currentFunction;
259:
260: static/*Function*/Object getCurrentFunction() {
261: return currentFunction;
262: }
263:
264: static void setCurrentFunction(/*Function*/Object f) {
265: currentFunction = f;
266: }
267:
268: /** The this parameter of the current function, or null. */
269: static Expression this Exp;
270:
271: /** override this when typechecking is needed. */
272: void typecheck() {
273: }
274:
275: final void doTypecheck() {
276: // avoid to typecheck twice
277: // usefull in bossa.syntax.Block for instance
278: if (typecheckingDone) {
279: //Internal.warning("Attempt to typecheck twice " + this + ", a " + getClass());
280: return;
281: }
282: typecheckingDone = true;
283:
284: typecheck();
285:
286: if (children != null)
287: for (Iterator i = children.iterator(); i.hasNext();)
288: try {
289: ((Node) i.next()).doTypecheck();
290: } catch (UserError ex) {
291: compilation.globalTypeScope.getPackage()
292: .getCompilation().error(ex);
293: }
294: }
295:
296: private boolean typecheckingDone = false;
297:
298: /****************************************************************
299: * Misc
300: ****************************************************************/
301:
302: protected VarScope scope;
303: protected TypeScope typeScope;
304:
305: protected List children;
306: private List varSymbols;
307: int propagate;
308: private List typeMapsSymbols, typeMapsNames;
309: }
|