Index: dart/site/try/poi/poi.dart |
diff --git a/dart/site/try/poi/poi.dart b/dart/site/try/poi/poi.dart |
index c013567abf122aeaae07f157908c2b8771b6195c..9a8ed95b651b1eeaf38723489abb2b2ce256da71 100644 |
--- a/dart/site/try/poi/poi.dart |
+++ b/dart/site/try/poi/poi.dart |
@@ -314,15 +314,21 @@ class ScriptOnlyFilter implements QueueFilter { |
} |
} |
+/** |
+ * Serializes scope information about an element. This is accomplished by |
+ * calling the [serialize] method on each element. Some elements need special |
+ * treatment, as their enclosing scope must also be serialized. |
+ */ |
class ScopeInformationVisitor extends ElementVisitor/* <void> */ { |
// TODO(ahe): Include function parameters and local variables. |
- final Element element; |
+ final Element currentElement; |
final int position; |
final StringBuffer buffer = new StringBuffer(); |
int indentationLevel = 0; |
+ ClassElement currentClass; |
- ScopeInformationVisitor(this.element, this.position); |
+ ScopeInformationVisitor(this.currentElement, this.position); |
String get indentation => ' ' * indentationLevel; |
@@ -334,27 +340,109 @@ class ScopeInformationVisitor extends ElementVisitor/* <void> */ { |
void visitLibraryElement(LibraryElement e) { |
bool isFirst = true; |
+ forEach(Element member) { |
+ if (!isFirst) { |
+ buffer.write(','); |
+ } |
+ buffer.write('\n'); |
+ indented; |
+ serialize(member); |
+ isFirst = false; |
+ } |
serialize( |
- e, omitEnclosing: true, |
+ e, |
+ // TODO(ahe): We omit the import scope if there is no current |
+ // class. That's wrong. |
+ omitEnclosing: currentClass == null, |
name: e.getLibraryName(), |
+ serializeEnclosing: () { |
+ // The enclosing scope of a library is a scope which contains all the |
+ // imported names. |
+ isFirst = true; |
+ buffer.write('{\n'); |
+ indentationLevel++; |
+ indented.write('"kind": "imports",\n'); |
+ indented.write('"members": ['); |
+ indentationLevel++; |
+ e.importScope.importScope.values.forEach(forEach); |
+ indentationLevel--; |
+ buffer.write('\n'); |
+ indented.write('],\n'); |
+ // The enclosing scope of the imported names scope is the superclass |
+ // scope of the current class. |
+ indented.write('"enclosing": '); |
+ serializeClassSide( |
+ currentClass.superclass, isStatic: false, includeSuper: true); |
+ buffer.write('\n'); |
+ indentationLevel--; |
+ indented.write('}'); |
+ }, |
serializeMembers: () { |
- // TODO(ahe): Include imported elements in libraries. |
- e.forEachLocalMember((Element member) { |
- if (!isFirst) { |
- buffer.write(','); |
- } |
- buffer.write('\n'); |
- indented; |
- serialize(member); |
- isFirst = false; |
- }); |
+ isFirst = true; |
+ e.localScope.values.forEach(forEach); |
}); |
} |
+ void visitClassElement(ClassElement e) { |
+ currentClass = e; |
+ serializeClassSide(e, isStatic: true); |
+ } |
+ |
+ /// Serializes one of the "sides" a class. The sides of a class are "instance |
+ /// side" and "class side". These terms are from Smalltalk. The instance side |
+ /// is all the local instance members of the class (the members of the |
+ /// mixin), and the class side is the equivalent for static members and |
+ /// constructors. |
+ /// The scope chain is ordered so that the "class side" is searched before |
+ /// the "instance side". |
+ void serializeClassSide( |
+ ClassElement e, |
+ {bool isStatic: false, |
+ bool omitEnclosing: false, |
+ bool includeSuper: false}) { |
+ bool isFirst = true; |
+ String name = e.name; |
+ var serializeEnclosing; |
+ if (isStatic) { |
+ serializeEnclosing = () { |
+ serializeClassSide(e, isStatic: false, omitEnclosing: omitEnclosing); |
+ }; |
+ } else { |
+ name = "this($name)"; |
+ } |
+ if (includeSuper) { |
+ assert(!omitEnclosing && !isStatic); |
+ if (e.superclass == null) { |
+ omitEnclosing = true; |
+ } else { |
+ // Members of the superclass are represented as a separate scope. |
+ serializeEnclosing = () { |
+ serializeClassSide( |
+ e.superclass, isStatic: false, omitEnclosing: false, |
+ includeSuper: true); |
+ }; |
+ } |
+ } |
+ serialize( |
+ e, omitEnclosing: omitEnclosing, serializeEnclosing: serializeEnclosing, |
+ name: name, serializeMembers: () { |
+ e.forEachLocalMember((Element member) { |
+ // Filter out members that don't belong to this "side". |
+ if (member.isStatic != isStatic) return; |
+ if (!isFirst) { |
+ buffer.write(','); |
+ } |
+ buffer.write('\n'); |
+ indented; |
+ serialize(member); |
+ isFirst = false; |
+ }); |
+ }); |
+ } |
+ |
void visitScopeContainerElement(ScopeContainerElement e) { |
bool isFirst = true; |
serialize(e, omitEnclosing: false, serializeMembers: () { |
- // TODO(ahe): Include inherited members in classes. |
e.forEachLocalMember((Element member) { |
if (!isFirst) { |
buffer.write(','); |
@@ -375,6 +463,7 @@ class ScopeInformationVisitor extends ElementVisitor/* <void> */ { |
Element element, |
{bool omitEnclosing: true, |
void serializeMembers(), |
+ void serializeEnclosing(), |
String name}) { |
DartType type; |
int category = element.kind.category; |
@@ -388,10 +477,12 @@ class ScopeInformationVisitor extends ElementVisitor/* <void> */ { |
} |
buffer.write('{\n'); |
indentationLevel++; |
- indented |
- ..write('"name": "') |
- ..write(name) |
- ..write('",\n'); |
+ if (name != '') { |
+ indented |
+ ..write('"name": "') |
+ ..write(name) |
+ ..write('",\n'); |
+ } |
indented |
..write('"kind": "') |
..write(element.kind) |
@@ -415,7 +506,11 @@ class ScopeInformationVisitor extends ElementVisitor/* <void> */ { |
if (!omitEnclosing) { |
buffer.write(',\n'); |
indented.write('"enclosing": '); |
- element.enclosingElement.accept(this); |
+ if (serializeEnclosing != null) { |
+ serializeEnclosing(); |
+ } else { |
+ element.enclosingElement.accept(this); |
+ } |
} |
indentationLevel--; |
buffer.write('\n'); |