001: /*
002: * xtc - The eXTensible Compiler
003: * Copyright (C) 2006-2007 IBM Corp.
004: *
005: * This program is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU General Public License
007: * version 2 as published by the Free Software Foundation.
008: *
009: * This program is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU General Public License for more details.
013: *
014: * You should have received a copy of the GNU General Public License
015: * along with this program; if not, write to the Free Software
016: * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
017: * USA.
018: */
019: package xtc.lang;
020:
021: import java.util.ArrayList;
022: import java.util.Iterator;
023: import java.util.List;
024:
025: import xtc.Constants;
026: import xtc.tree.Attribute;
027: import xtc.tree.GNode;
028: import xtc.tree.Node;
029: import xtc.tree.Visitor;
030: import xtc.type.AliasT;
031: import xtc.type.ClassOrInterfaceT;
032: import xtc.type.ClassT;
033: import xtc.type.InterfaceT;
034: import xtc.type.Language;
035: import xtc.type.MethodT;
036: import xtc.type.PackageT;
037: import xtc.type.Type;
038: import xtc.type.VariableT;
039: import xtc.util.Runtime;
040: import xtc.util.SymbolTable;
041: import xtc.util.Utilities;
042:
043: /**
044: * A visitor that constructs externally visible types and fills the symbol table
045: * for a Java file. Does not descend into method bodies, just finds the class,
046: * interface, method, and field signatures. Used in conjunction with
047: * JavaAnalyzer. Let F be the file currently analyzed by the JavaAnalyzer; then
048: * the JavaExternalAnalyzer is used on (i) classes defined in F, and (ii)
049: * compilation units that define classes whose name gets used in F. Packages,
050: * classes, and interfaces go into namespace "tag(..)", methods go into
051: * namespace "method(..)", and fields go into the default namespace. The scopes
052: * associated with packages and types do not have the namespace in their name,
053: * only the symbols do. For example, scope "java" contains scope "lang", but
054: * scope "java" maps symbol "tag(lang)" to an instance of PackageT. Declared
055: * types are represented by instances of ClassT or InterfaceT, whereas names
056: * used, for example, as method return types are represented by instances of
057: * AliasT.
058: *
059: * @author Martin Hirzel
060: * @version $Revision: 1.71 $
061: */
062: public class JavaExternalAnalyzer extends Visitor {
063: protected static List<Attribute> MODIFIERS_CLASS = new ArrayList<Attribute>();
064:
065: protected static List<Attribute> MODIFIERS_CONSTRUCTOR = new ArrayList<Attribute>();
066:
067: protected static List<Attribute> MODIFIERS_FIELD = new ArrayList<Attribute>();
068:
069: protected static List<Attribute> MODIFIERS_INTERFACE = new ArrayList<Attribute>();
070:
071: protected static List<Attribute> MODIFIERS_INTERFACE_FIELD = new ArrayList<Attribute>();
072:
073: protected static List<Attribute> MODIFIERS_INTERFACE_MEMBERTYPE = new ArrayList<Attribute>();
074:
075: protected static List<Attribute> MODIFIERS_INTERFACE_METHOD = new ArrayList<Attribute>();
076:
077: protected static List<Attribute> MODIFIERS_METHOD = new ArrayList<Attribute>();
078:
079: static {
080: // gosling_et_al_2000 8.1.1
081: MODIFIERS_CLASS.add(JavaEntities.nameToModifier("public"));
082: MODIFIERS_CLASS.add(JavaEntities.nameToModifier("protected"));
083: MODIFIERS_CLASS.add(JavaEntities.nameToModifier("private"));
084: MODIFIERS_CLASS.add(JavaEntities.nameToModifier("abstract"));
085: MODIFIERS_CLASS.add(JavaEntities.nameToModifier("static"));
086: MODIFIERS_CLASS.add(JavaEntities.nameToModifier("final"));
087: MODIFIERS_CLASS.add(JavaEntities.nameToModifier("strictfp"));
088: // gosling_et_al_2000 8.3.1
089: MODIFIERS_FIELD.add(JavaEntities.nameToModifier("public"));
090: MODIFIERS_FIELD.add(JavaEntities.nameToModifier("protected"));
091: MODIFIERS_FIELD.add(JavaEntities.nameToModifier("private"));
092: MODIFIERS_FIELD.add(JavaEntities.nameToModifier("static"));
093: MODIFIERS_FIELD.add(JavaEntities.nameToModifier("final"));
094: MODIFIERS_FIELD.add(JavaEntities.nameToModifier("transient"));
095: MODIFIERS_FIELD.add(JavaEntities.nameToModifier("volatile"));
096: // gosling_et_al_2000 8.8
097: MODIFIERS_CONSTRUCTOR
098: .add(JavaEntities.nameToModifier("public"));
099: MODIFIERS_CONSTRUCTOR.add(JavaEntities
100: .nameToModifier("protected"));
101: MODIFIERS_CONSTRUCTOR.add(JavaEntities
102: .nameToModifier("private"));
103: // gosling_et_al_2000 9.1.1
104: MODIFIERS_INTERFACE.add(JavaEntities.nameToModifier("public"));
105: MODIFIERS_INTERFACE.add(JavaEntities
106: .nameToModifier("protected"));
107: MODIFIERS_INTERFACE.add(JavaEntities.nameToModifier("private"));
108: MODIFIERS_INTERFACE
109: .add(JavaEntities.nameToModifier("abstract"));
110: MODIFIERS_INTERFACE.add(JavaEntities.nameToModifier("static"));
111: MODIFIERS_INTERFACE
112: .add(JavaEntities.nameToModifier("strictfp"));
113: // gosling_et_al_2000 9.5
114: MODIFIERS_INTERFACE_FIELD.add(JavaEntities
115: .nameToModifier("public"));
116: MODIFIERS_INTERFACE_FIELD.add(JavaEntities
117: .nameToModifier("static"));
118: MODIFIERS_INTERFACE_FIELD.add(JavaEntities
119: .nameToModifier("final"));
120: // gosling_et_al_2000 9.5
121: MODIFIERS_INTERFACE_MEMBERTYPE.add(JavaEntities
122: .nameToModifier("static"));
123: MODIFIERS_INTERFACE_MEMBERTYPE.add(JavaEntities
124: .nameToModifier("public"));
125: // gosling_et_al_2000 9.4
126: MODIFIERS_INTERFACE_METHOD.add(JavaEntities
127: .nameToModifier("public"));
128: MODIFIERS_INTERFACE_METHOD.add(JavaEntities
129: .nameToModifier("abstract"));
130: // gosling_et_al_2000 8.4.3
131: MODIFIERS_METHOD.add(JavaEntities.nameToModifier("public"));
132: MODIFIERS_METHOD.add(JavaEntities.nameToModifier("protected"));
133: MODIFIERS_METHOD.add(JavaEntities.nameToModifier("private"));
134: MODIFIERS_METHOD.add(JavaEntities.nameToModifier("abstract"));
135: MODIFIERS_METHOD.add(JavaEntities.nameToModifier("static"));
136: MODIFIERS_METHOD.add(JavaEntities.nameToModifier("final"));
137: MODIFIERS_METHOD.add(JavaEntities
138: .nameToModifier("synchronized"));
139: MODIFIERS_METHOD.add(JavaEntities.nameToModifier("native"));
140: MODIFIERS_METHOD.add(JavaEntities.nameToModifier("strictfp"));
141: }
142:
143: protected static void addModifier(final List<Attribute> modifiers,
144: final String name) {
145: if (!hasModifier(modifiers, name))
146: modifiers.add(JavaEntities.nameToModifier(name));
147: }
148:
149: protected static void addModifiers(final List<Attribute> modifiers,
150: final List<Attribute> toAdd) {
151: for (final Attribute attribute : toAdd)
152: if (!modifiers.contains(attribute))
153: modifiers.add(attribute);
154: }
155:
156: public static int countDimensions(final GNode dimNode) {
157: return null == dimNode ? 0 : dimNode.size();
158: }
159:
160: protected static boolean hasModifier(
161: final List<Attribute> modifiers, final String modifier) {
162: return modifiers
163: .contains(JavaEntities.nameToModifier(modifier));
164: }
165:
166: protected final Runtime _runtime;
167:
168: public final SymbolTable _table;
169:
170: public JavaExternalAnalyzer(final Runtime runtime,
171: final SymbolTable table) {
172: _runtime = runtime;
173: _table = table;
174: }
175:
176: /** Use this for asserting that the input is typed correctly. */
177: protected boolean assrt(final GNode n, final boolean cond,
178: final String msgFormat, final Object... msgArgs) {
179: return JavaEntities.runtimeAssrt(_runtime, n, cond, msgFormat,
180: msgArgs);
181: }
182:
183: protected void assrtDiffersFromEnclosing(final GNode n,
184: final String canonicalName) {
185: final String simpleName = Utilities.getName(canonicalName);
186: final String packageName = JavaEntities.currentPackage(_table)
187: .getName();
188: final String nameWithoutPackage = 0 == packageName.length() ? canonicalName
189: : canonicalName.substring(packageName.length() + 1);
190: final String middleName = Utilities
191: .getQualifier(nameWithoutPackage);
192: if (null != middleName) {
193: final String[] c = Utilities.toComponents(middleName);
194: for (int i = 0; i < c.length; i++)
195: assrt(n, !c[i].equals(simpleName),
196: "name must not match enclosing type");
197: }
198: }
199:
200: protected void assrtLegalModifiers(final GNode n,
201: final List<Attribute> expected,
202: final List<Attribute> actual, final String context) {
203: final boolean pri = hasModifier(actual, "private");
204: final boolean pro = hasModifier(actual, "protected");
205: final boolean pub = hasModifier(actual, "public");
206: assrt(n, !(pri && pro),
207: "conflicting modifiers private and protected");
208: assrt(n, !(pri && pub),
209: "conflicting modifiers private and public");
210: assrt(n, !(pro && pub),
211: "conflicting modifiers protected and public");
212: for (final Attribute m : actual)
213: assrt(n, expected.contains(m), "illegal %s modifier %s",
214: context, m);
215: final boolean fin = hasModifier(actual, "final");
216: final boolean vol = hasModifier(actual, "volatile");
217: assrt(n, !(fin && vol),
218: "conflicting modifiers final and volatile");
219: }
220:
221: protected final String currentScopeName() {
222: return _table.current().getQualifiedName();
223: }
224:
225: protected final Type declareDefaultConstructorIfNecessary() {
226: // gosling_et_al_2000 8.8.7 default constructor
227: final Type wrappedBase = JavaEntities.currentType(_table);
228: final ClassOrInterfaceT base = JavaEntities
229: .resolveToRawClassOrInterfaceT(wrappedBase);
230: for (final Type i : base.getMethods())
231: if (JavaEntities.isConstructor(base, i.toMethod()))
232: return null;
233: final MethodT result = JavaEntities.newRawConstructor(base,
234: new ArrayList<Type>(), new ArrayList<Type>());
235: final List<Attribute> modifiers = new ArrayList<Attribute>();
236: if (JavaEntities.hasModifier(wrappedBase, "private"))
237: modifiers.add(JavaEntities.nameToModifier("private"));
238: else if (JavaEntities.hasModifier(wrappedBase, "protected"))
239: modifiers.add(JavaEntities.nameToModifier("protected"));
240: else if (JavaEntities.hasModifier(wrappedBase, "public"))
241: modifiers.add(JavaEntities.nameToModifier("public"));
242: for (final Attribute mod : modifiers)
243: result.addAttribute(mod);
244: final String symbol = "method(<init>)()";
245: _table.current().define(symbol, result);
246: _table.enter(symbol);
247: result.scope(_table.current().getQualifiedName());
248: _table.exit();
249: assert JavaEntities.isConstructor(base, result);
250: JavaEntities.currentType(_table).getMethods().add(result);
251: return result;
252: }
253:
254: protected final List<Type> makeList(final GNode n) {
255: final List<Type> result = new ArrayList<Type>(n.size());
256: for (final Object o : n)
257: result.add((Type) dispatch((Node) o));
258: return result;
259: }
260:
261: protected final boolean memberOfInterface() {
262: if (!JavaEntities.isScopeForMember(currentScopeName()))
263: return false;
264: final Type t = JavaEntities.currentType(_table);
265: return null != t && JavaEntities.isWrappedInterfaceT(t);
266: }
267:
268: public final List<Type> processDeclarators(
269: final List<Attribute> modifiers, final Type type,
270: final GNode declarators) {
271: assert JavaEntities.isRValueT(type);
272: final List<Type> result = new ArrayList<Type>();
273: final boolean isLocal = JavaEntities
274: .isScopeLocal(currentScopeName());
275: for (final Object i : declarators) {
276: final GNode declNode = (GNode) i;
277: final String name = declNode.getString(0);
278: final Type dimType = JavaEntities.typeWithDimensions(type,
279: countDimensions(declNode.getGeneric(1)));
280: final Type entity = isLocal ? VariableT.newLocal(dimType,
281: name) : VariableT.newField(dimType, name);
282: for (final Attribute mod : modifiers)
283: entity.addAttribute(mod);
284: entity.language(Language.JAVA);
285: assert isLocal ? JavaEntities.isLocalT(entity)
286: : JavaEntities.isFieldT(entity);
287: if (null == _table.current().lookupLocally(name)) {
288: result.add(entity);
289: _table.current().define(name, entity);
290: entity.scope(_table.current().getQualifiedName());
291: if (!isLocal)
292: JavaEntities.currentType(_table).getFields().add(
293: entity);
294: } else {
295: if (isLocal)
296: _runtime.error("duplicate variable declaration "
297: + name, declNode);
298: else
299: _runtime.error("duplicate field declaration "
300: + name, declNode);
301: }
302: declNode.setProperty(Constants.TYPE, entity);
303: }
304: return result;
305: }
306:
307: /** Visit a BlockDeclaration = ["static"] Block (gosling_et_al_2000 <a
308: * href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#246032">§8.6</a>,
309: * <a
310: * href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#39245">§8.7</a>). */
311: public final void visitBlockDeclaration(final GNode n) {
312: assert 2 == n.size();
313: }
314:
315: /**
316: * Visit a ClassBody = Declaration* (gosling_et_al_2000 <a
317: * href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#18988">§8.1.5</a>,
318: * <a
319: * href="http://java.sun.com/docs/books/jls/second_edition/html/interfaces.doc.html#236431">§9.1.3</a>,
320: * <a
321: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#41147">§15.9</a>).
322: */
323: public final void visitClassBody(final GNode n) {
324: for (final Object o : n)
325: dispatch((Node) o);
326: }
327:
328: /**
329: * Visit a ClassDeclaration = Modifiers Identifier null [Extension]
330: * [Implementation] ClassBody (gosling_et_al_2000 <a
331: * href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#15372">§8.1</a>,
332: * <a
333: * href="http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#247766">§14.3</a>).
334: */
335: public final ClassT visitClassDeclaration(final GNode n) {
336: @SuppressWarnings("unchecked")
337: final List<Attribute> modifiers = (List<Attribute>) dispatch(n
338: .getNode(0));
339: final boolean isMember = JavaEntities
340: .isScopeForMember(currentScopeName());
341: if (isMember) {
342: final ClassOrInterfaceT declaringType = JavaEntities
343: .currentType(_table);
344: if (JavaEntities.isWrappedInterfaceT(declaringType))
345: addModifiers(modifiers, MODIFIERS_INTERFACE_MEMBERTYPE);
346: if (JavaEntities.hasModifier(declaringType, "strictfp"))
347: addModifier(modifiers, "strictfp");
348: if (hasModifier(modifiers, "static"))
349: assrt(n, JavaEntities.hasModifier(declaringType,
350: "static")
351: || JavaEntities.isTypeTopLevel(declaringType),
352: "illegal context for static member");
353: }
354: assrtLegalModifiers(n.getGeneric(0), MODIFIERS_CLASS,
355: modifiers, "class");
356: if (hasModifier(modifiers, "public"))
357: assrt(
358: n,
359: isMember
360: || JavaEntities
361: .isScopeTopLevel(currentScopeName()),
362: "public class must be member or top-level");
363: if (hasModifier(modifiers, "protected")
364: || hasModifier(modifiers, "private"))
365: assrt(n, isMember && !memberOfInterface(),
366: "private or protected class must be member of class");
367: if (hasModifier(modifiers, "static"))
368: assrt(n, isMember, "static class must be member");
369: assrt(n, !hasModifier(modifiers, "final")
370: || !hasModifier(modifiers, "abstract"),
371: "can not be both abstract and final");
372: final String simpleName = n.getString(1);
373: final String canonicalName = JavaEntities.canonicalName(_table,
374: simpleName);
375: assrtDiffersFromEnclosing(n, canonicalName);
376: final List<Type> extension = JavaEntities
377: .typeList((List) dispatch(n.getNode(3)));
378: final Type parent;
379: if (null == extension) {
380: parent = JavaEntities.tObjectAlias(_table);
381: } else {
382: assrt(n, 1 == extension.size(), "can only extend one class");
383: assrt(n, !"java.lang.Object".equals(canonicalName),
384: "Object can not have an extends clause");
385: parent = extension.get(0);
386: }
387: assrt(n.getGeneric(0), JavaEntities.isWrappedClassT(parent),
388: "class can only extend class");
389: final List<Type> interfaces = n.get(4) == null ? new ArrayList<Type>()
390: : JavaEntities.typeList((List) dispatch(n.getNode(4)));
391: if ("java.lang.Object".equals(canonicalName))
392: assrt(n, 0 == interfaces.size(),
393: "Object can not have an implements clause");
394: for (final Type i : interfaces)
395: assrt(n.getGeneric(4), JavaEntities.isWrappedInterfaceT(i),
396: "class can only implement interface");
397: final ClassT result = new ClassT(canonicalName, parent,
398: interfaces, new ArrayList<Type>(),
399: new ArrayList<Type>());
400: for (final Attribute mod : modifiers)
401: result.addAttribute(mod);
402: final String tagName = SymbolTable.toTagName(simpleName);
403: assert null == _table.current().lookupLocally(tagName);
404: _table.current().define(tagName, result);
405: _table.enter(simpleName);
406: result.scope(_table.current().getQualifiedName());
407: dispatch(n.getNode(5));
408: declareDefaultConstructorIfNecessary();
409: _table.exit();
410: assert result.isClass();
411: return result;
412: }
413:
414: /**
415: * Visit a CompilationUnit = [PackageDeclaration] ImportDeclaration*
416: * Declaration* (gosling_et_al_2000 <a
417: * href="http://java.sun.com/docs/books/jls/second_edition/html/packages.doc.html#40031">§7.3</a>).
418: */
419: public final void visitCompilationUnit(final GNode n) {
420: if (null == n.get(0))
421: visitPackageDeclaration(null);
422: else
423: dispatch(n.getNode(0));
424: _table.enter(JavaEntities
425: .fileNameToScopeName(n.getLocation().file));
426: for (int i = 1; i < n.size(); i++) {
427: final GNode declNode = n.getGeneric(i);
428: assrt(n, declNode.hasName("ImportDeclaration")
429: || declNode.hasName("ClassDeclaration")
430: || declNode.hasName("InterfaceDeclaration")
431: || declNode.hasName("EmptyDeclaration"),
432: "unexpected top-level %s", declNode.getName());
433: dispatch(declNode);
434: }
435: _table.setScope(_table.root());
436: }
437:
438: /**
439: * Visit a EmptyDeclaration = (no children) (gosling_et_al_2000 <a
440: * href="http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#5970">§14.6</a>).
441: */
442: public final void visitEmptyDeclaration(final GNode n) {
443: assert 0 == n.size();
444: }
445:
446: /** Visit an Extension = Type+. */
447: public final List<Type> visitExtension(final GNode n) {
448: // gosling_et_al_2000 8.1.3, 9.1.2
449: final List<Type> result = makeList(n);
450: for (final Type t : result)
451: assrt(n, JavaEntities.isWrappedClassT(t)
452: || JavaEntities.isWrappedInterfaceT(t),
453: "supertype must be class or interface");
454: return result;
455: }
456:
457: /**
458: * Visit a FieldDeclaration = Modifiers Type Declarators.
459: * Also descends into Declarators = Declarator+ and into
460: * Declarator = Identifier [Dimensions] [VariableInitializer]
461: * to get all the fields declared by this node.
462: */
463: public final List<Type> visitFieldDeclaration(final GNode n) {
464: // gosling_et_al_2000 9.3
465: @SuppressWarnings("unchecked")
466: final List<Attribute> modifiers = (List<Attribute>) dispatch(n
467: .getNode(0));
468: if (memberOfInterface()) {
469: addModifiers(modifiers, MODIFIERS_INTERFACE_FIELD);
470: assrtLegalModifiers(n, MODIFIERS_INTERFACE_FIELD,
471: modifiers, "interface field");
472: } else {
473: assrtLegalModifiers(n, MODIFIERS_FIELD, modifiers, "field");
474: }
475: final Type type = (Type) dispatch(n.getNode(1));
476: assrt(n.getGeneric(1), JavaEntities.isRValueT(type),
477: "illegal type for field");
478: return processDeclarators(modifiers, type, n.getGeneric(2));
479: }
480:
481: /** Visit a FormalParameter = [Modifier] Type null Identifier [Dimensions]. */
482: public final Type visitFormalParameter(final GNode n) {
483: // gosling_et_al_2000 8.4.1
484: assert null == n.get(4) : "must run JavaAstSimplifier first";
485: final String id = n.getString(3);
486: final Type result = VariableT.newParam((Type) dispatch(n
487: .getNode(1)), id);
488: result.language(Language.JAVA);
489: if (n.getGeneric(0).size() != 0)
490: result.addAttribute(JavaEntities.nameToModifier("final"));
491: if (null == _table.current().lookupLocally(id)) {
492: _table.current().define(id, result);
493: result.scope(_table.current().getQualifiedName());
494: } else
495: _runtime.error("duplicate parameter declaration " + id, n);
496: assert JavaEntities.isParameterT(result);
497: return result;
498: }
499:
500: /** Visit a FormalParameters = FormalParameter*. */
501: public final List<Type> visitFormalParameters(final GNode n) {
502: // gosling_et_al_2000 8.4.1
503: return makeList(n);
504: }
505:
506: /** Visit an Implementation = Type+. */
507: public final List<Type> visitImplementation(final GNode n) {
508: // gosling_et_al_2000 8.1.4
509: final List<Type> result = makeList(n);
510: for (final Iterator iN = n.iterator(), iT = result.iterator(); iT
511: .hasNext();)
512: assrt((GNode) iN.next(), JavaEntities
513: .isWrappedInterfaceT((Type) iT.next()),
514: "supertype must be class or interface");
515: return result;
516: }
517:
518: /** Visit an ImportDeclaration = QualifiedIdentifier ["*"]. */
519: public final void visitImportDeclaration(final GNode n) {
520: // gosling_et_al_2000 7.5
521: final String canonicalName = (String) dispatch(n.getNode(1));
522: if (n.get(2) == null) {
523: // defer resolution to JavaAnalyzer.visitPrimaryIdentifier()
524: final AliasT t = new AliasT(canonicalName);
525: final String simpleName = Utilities
526: .unqualify(canonicalName);
527: // TD 03 (7.5) ImportDeclaration = QualifiedIdentifier ["*"] (check whether the name clashes with some existing package)
528: assrt(n, JavaEntities.isWrappedClassT(t)
529: || JavaEntities.isWrappedInterfaceT(t),
530: "import must be class or interface");
531: _table.current().define(SymbolTable.toTagName(simpleName),
532: t);
533: } else {
534: final PackageT t = JavaEntities.canonicalNameToPackage(
535: _table, canonicalName);
536: _table.current().addDefinition("imports(*)", t);
537: }
538: }
539:
540: /** Visit a InterfaceDeclaration = Modifiers Identifier null [Extension] ClassBody. */
541: public final InterfaceT visitInterfaceDeclaration(final GNode n) {
542: // gosling_et_al_2000 9.1
543: @SuppressWarnings("unchecked")
544: final List<Attribute> modifiers = (List<Attribute>) dispatch(n
545: .getNode(0));
546: addModifier(modifiers, "abstract");
547: final boolean isMember = JavaEntities
548: .isScopeForMember(currentScopeName());
549: if (isMember) {
550: final ClassOrInterfaceT declaringType = JavaEntities
551: .currentType(_table);
552: if (declaringType.isInterface())
553: addModifiers(modifiers, MODIFIERS_INTERFACE_MEMBERTYPE);
554: if (JavaEntities.hasModifier(declaringType, "strictfp"))
555: addModifier(modifiers, "strictfp");
556: addModifier(modifiers, "static");
557: assrt(n, JavaEntities.hasModifier(declaringType, "static")
558: || JavaEntities.isTypeTopLevel(declaringType),
559: "illegal context for static member");
560: }
561: if (hasModifier(modifiers, "protected")
562: || hasModifier(modifiers, "private"))
563: assrt(n, isMember,
564: "private or protected interface must be member");
565: if (hasModifier(modifiers, "static"))
566: assrt(n, isMember, "static interface must be member");
567: assrtLegalModifiers(n, MODIFIERS_INTERFACE, modifiers,
568: "interface");
569: final String simpleName = n.getString(1);
570: final String canonicalName = JavaEntities.canonicalName(_table,
571: simpleName);
572: assrtDiffersFromEnclosing(n, canonicalName);
573: final List<Type> interfaces = null == n.get(3) ? new ArrayList<Type>()
574: : JavaEntities.typeList((List) dispatch(n.getNode(3)));
575: final InterfaceT result = new InterfaceT(canonicalName,
576: interfaces, new ArrayList<Type>(),
577: new ArrayList<Type>());
578: for (final Attribute mod : modifiers)
579: result.addAttribute(mod);
580: final String tagName = SymbolTable.toTagName(simpleName);
581: if (null == _table.current().lookupLocally(tagName)) {
582: _table.current().define(tagName, result);
583: _table.enter(simpleName);
584: result.scope(_table.current().getQualifiedName());
585: final GNode bodyNode = n.getGeneric(4);
586: for (int i = 0; i < bodyNode.size(); i++) {
587: final GNode memberNode = bodyNode.getGeneric(i);
588: assrt(n, memberNode.hasName("EmptyDeclaration")
589: || memberNode.hasName("FieldDeclaration")
590: || memberNode.hasName("MethodDeclaration")
591: || memberNode.hasName("ClassDeclaration")
592: || memberNode.hasName("InterfaceDeclaration"),
593: "illegal interface member");
594: dispatch(memberNode);
595: }
596: _table.exit();
597: if (JavaEntities.isTypeNested(result))
598: assrt(n, !JavaEntities.isTypeInner(JavaEntities
599: .declaringType(_table, result)),
600: "inner classes may not declare member interfaces");
601: } else {
602: _runtime.error("duplicate declaration " + canonicalName, n);
603: }
604: assert result.isInterface();
605: return result;
606: }
607:
608: /**
609: * Visit a MethodDeclaration = Modifiers null Type Identifier FormalParameters [Dimensions]
610: * [ThrowsClause] [Block].
611: */
612: public final Type visitMethodDeclaration(final GNode n) {
613: // gosling_et_al_2000 8.4, 8.8, 9.4
614: assert null == n.get(5) : "must run JavaAstSimplifier first";
615: @SuppressWarnings("unchecked")
616: final List<Attribute> modifiers = (List<Attribute>) dispatch(n
617: .getNode(0));
618: final String name = n.getString(3);
619: final ClassOrInterfaceT base = JavaEntities.currentType(_table);
620: final boolean isConstructor = JavaEntities.typeToSimpleName(
621: base).equals(name);
622: final Type returnType = isConstructor ? (JavaEntities
623: .constructorsReturnVoid() ? JavaEntities
624: .nameToBaseType("void") : base) : (Type) dispatch(n
625: .getNode(2));
626: if (!isConstructor) {
627: assrt(n, null != n.get(2), "missing return type");
628: if (JavaEntities.hasModifier(base, "strictfp"))
629: addModifier(modifiers, "strictfp");
630: if (JavaEntities.hasModifier(base, "final"))
631: addModifier(modifiers, "final");
632: if (hasModifier(modifiers, "private"))
633: addModifier(modifiers, "final");
634: }
635: if (memberOfInterface()) {
636: assrt(n, !isConstructor,
637: "interface can not have constructor");
638: addModifiers(modifiers, MODIFIERS_INTERFACE_METHOD);
639: assrtLegalModifiers(n, MODIFIERS_INTERFACE_METHOD,
640: modifiers, "interface method");
641: } else {
642: if (isConstructor)
643: assrtLegalModifiers(n, MODIFIERS_CONSTRUCTOR,
644: modifiers, "constructor");
645: else
646: assrtLegalModifiers(n, MODIFIERS_METHOD, modifiers,
647: "method");
648: }
649: if (hasModifier(modifiers, "static"))
650: assrt(n, JavaEntities.hasModifier(base, "static")
651: || JavaEntities.isTypeTopLevel(base),
652: "illegal context for static member");
653: final List<Type> exceptions = null == n.get(6) ? new ArrayList<Type>()
654: : JavaEntities.typeList((List) dispatch(n.getNode(6)));
655: final String symbol = JavaEntities.methodSymbolFromAst(n);
656: _table.enter(symbol);
657: final List<Type> parameters = JavaEntities
658: .typeList((List) dispatch(n.getNode(4)));
659: final Type result = new MethodT(returnType, name, parameters,
660: false, exceptions);
661: for (final Attribute mod : modifiers)
662: result.addAttribute(mod);
663: if (JavaEntities.hasModifier(result, "abstract"))
664: assrt(n, !JavaEntities.hasModifier(result, "private")
665: && !JavaEntities.hasModifier(result, "static")
666: && !JavaEntities.hasModifier(result, "final")
667: && !JavaEntities.hasModifier(result, "native")
668: && !JavaEntities.hasModifier(result, "strictfp")
669: && !JavaEntities
670: .hasModifier(result, "synchronized"),
671: "conflicting modifiers");
672: assrt(n, !JavaEntities.hasModifier(result, "strictfp")
673: || !JavaEntities.hasModifier(result, "native"),
674: "conflicting modifiers");
675: result.scope(_table.current().getQualifiedName());
676: _table.exit();
677: _table.current().define(symbol, result);
678: JavaEntities.currentType(_table).getMethods().add(result);
679: assert result.isMethod();
680: return result;
681: }
682:
683: /** Visit a Modifiers = Modifier*. */
684: public final List<Attribute> visitModifiers(final GNode n) {
685: final List<Attribute> result = new ArrayList<Attribute>();
686: for (int i = 0; i < n.size(); i++) {
687: final String name = n.getGeneric(i).getString(0);
688: final Attribute modifier = JavaEntities
689: .nameToModifier(name);
690: if (null == modifier)
691: _runtime.error("unexpected modifier " + name, n);
692: else if (result.contains(modifier))
693: _runtime.error("duplicate modifier " + name, n);
694: else
695: result.add(modifier);
696: }
697: return result;
698: }
699:
700: /** Visit a PackageDeclaration = QualifiedIdentifier. */
701: public final PackageT visitPackageDeclaration(final GNode n) {
702: // gosling_et_al_2000 9.4
703: final String canonicalName = null == n ? ""
704: : (String) dispatch(n.getNode(1));
705: final PackageT result = JavaEntities.canonicalNameToPackage(
706: _table, canonicalName);
707: _table.enter(JavaEntities.packageNameToScopeName(result
708: .getName()));
709: return result;
710: }
711:
712: /** Visit a PrimitiveType = ("byte" / "short" / "char" / "int" / "long" / "float" / "double" / "boolean")
713: * (gosling_et_al_2000 <a href="http://java.sun.com/docs/books/jls/second_edition/html/typesValues.doc.html#85587">§4.2</a>). */
714: public final Type visitPrimitiveType(final GNode n) {
715: final Type result = JavaEntities.nameToBaseType(n.getString(0));
716: assrt(n, null != result
717: && (JavaEntities.isPrimitiveT(result) || result
718: .isVoid()), "unknown base type %s", n
719: .getString(0));
720: return result;
721: }
722:
723: /** Visit a QualifiedIdentifier = Identifier+. */
724: public final String visitQualifiedIdentifier(final GNode n) {
725: // using StringBuffer instead of Utilities.qualify() to avoid O(n^2)
726: // behavior
727: final StringBuffer b = new StringBuffer();
728: for (int i = 0; i < n.size(); i++) {
729: if (b.length() > 0)
730: b.append(Constants.QUALIFIER);
731: b.append(n.getString(i));
732: }
733: return b.toString();
734: }
735:
736: /** Visit a ThrowsClause = QualifiedIdentifier+. */
737: public final List<Type> visitThrowsClause(final GNode n) {
738: //gosling_et_al_2000 8.4.4, 8.8.4, 9.4
739: final List<Type> result = new ArrayList<Type>(n.size());
740: for (int i = 0; i < n.size(); i++) {
741: final String name = (String) dispatch(n.getNode(i));
742: result.add(new AliasT(name));
743: }
744: return result;
745: }
746:
747: /**
748: * Visit a Type = TypeName Dimensions
749: * (gosling_et_al_2000 <a href="http://java.sun.com/docs/books/jls/second_edition/html/typesValues.doc.html#48440">§4</a>,
750: * <a href="http://java.sun.com/docs/books/jls/second_edition/html/arrays.doc.html#25518">§10.1</a>).
751: * Note that TypeName is either PrimitiveType or ClassType, i.e., QualifiedIdentifier.
752: * Make no resolution attempt in the case of a qualified identifier, just
753: * return an alias every time. The reason is that in general, there is
754: * too little information to resolve the type at this point. For example, the
755: * name may refer to a type declared in another file, which may recursively
756: * mention an entity in this file.
757: */
758: public final Type visitType(final GNode n) {
759: final boolean composite = n.getGeneric(0).hasName(
760: "QualifiedIdentifier");
761: final Object dispatched0 = dispatch(n.getNode(0));
762: final Type componentT = composite ? new AliasT(
763: (String) dispatched0) : (Type) dispatched0;
764: final int dimensions = countDimensions(n.getGeneric(1));
765: final Type result = JavaEntities.typeWithDimensions(componentT,
766: dimensions);
767: assrt(n, JavaEntities.isReturnT(result),
768: "unexpected type reference");
769: return result;
770: }
771:
772: /** Visit a VoidType = (no children). */
773: public final Type visitVoidType(final GNode n) {
774: return JavaEntities.nameToBaseType("void");
775: }
776: }
|