Chromium Code Reviews| Index: lib/compiler/implementation/dart_backend/placeholder_collector.dart |
| diff --git a/lib/compiler/implementation/dart_backend/placeholder_collector.dart b/lib/compiler/implementation/dart_backend/placeholder_collector.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..57bec4fe4afb80a032041c6019c5a83c7e1142b8 |
| --- /dev/null |
| +++ b/lib/compiler/implementation/dart_backend/placeholder_collector.dart |
| @@ -0,0 +1,153 @@ |
| +// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| +// for details. All rights reserved. Use of this source code is governed by a |
| +// BSD-style license that can be found in the LICENSE file. |
| + |
| +class SendVisitor extends ResolvedVisitor { |
| + final PlaceholderCollector collector; |
| + |
| + SendVisitor(this.collector, TreeElements elements) : super(elements); |
| + |
| + visitSuperSend(Send node) {} |
| + visitOperatorSend(Send node) {} |
| + visitClosureSend(Send node) {} |
| + visitDynamicSend(Send node) {} |
| + visitForeignSend(Send node) {} |
| + |
| + visitGetterSend(Send node) { |
| + final element = elements[node]; |
| + // element === null means dynamic property access. |
|
Anton Muhin
2012/08/08 08:27:20
what !isTopLevel() means?
Roman
2012/08/09 05:02:35
added comment that we don't want to rename non-top
|
| + if (element === null || !element.isTopLevel()) return; |
| + // Unqualified <class> in static invocation, why it's not a type annotation? |
| + // Another option would be to process in visitStaticSend, NB: |
| + // those elements are not top-level. |
| + // OR: unqualified top level. |
| + collector.placeholderForElement(node.selector, element); |
|
Anton Muhin
2012/08/08 08:27:20
nit: placeholderForElement makes me think it shoul
Roman
2012/08/09 05:02:35
Done.
|
| + if (node.receiver !== null) { |
| + // <lib prefix>.<top level>. |
| + collector.placeholderForNull(node.receiver); // Cut library prefix. |
| + } |
| + } |
| + |
| + visitStaticSend(Send node) { |
| + final element = elements[node]; |
| + if (!element.isTopLevel()) return; |
| + // Another ugly case: <lib prefix>.<top level> is represented as |
| + // receiver: lib prefix, selector: top level. |
| + collector.placeholderForMethod(node.selector, element); |
| + if (node.receiver !== null) { |
| + assert(elements[node.receiver].isPrefix()); |
| + // Hack: putting null into map overrides receiver of original node. |
| + collector.placeholderForNull(node.receiver); |
| + } |
| + } |
| +} |
| + |
| +class PlaceholderCollector extends AbstractVisitor { |
| + final Compiler compiler; |
| + final Map<Node, Placeholder> placeholders; |
| + Element currentElement; |
| + TreeElements treeElements; |
| + |
| + PlaceholderCollector(this.compiler) : |
| + placeholders = new Map<Node, Placeholder>(); |
| + |
| + void processFunction(FunctionElement element, Node node) { |
|
Anton Muhin
2012/08/08 08:27:20
nit: process (here and in the method below) is too
Roman
2012/08/09 05:02:35
Done.
|
| + if (element.isGenerativeConstructor() || element.isFactoryConstructor()) { |
| + // Two complicated cases for class/interface renaming: |
| + // 1) class which implements constructors of other interfaces, but not |
| + // implements interfaces themselves: |
| + // 0.dart: class C { I(); } |
| + // 1.dart and 2.dart: interface I default C { I(); } |
| + // now we have to duplicate our I() constructor in C class with |
| + // proper names. |
| + // 2) (even worse for us): |
| + // 0.dart: class C { C(); } |
| + // 1.dart: interface C default p0.C { C(); } |
| + // the second case is just a bug now. |
| + final enclosingClass = element.getEnclosingClass(); |
| + Node nameNode = node.name; |
| + if (nameNode is Send) nameNode = nameNode.receiver; |
| + // For cases like class C implements I { I(); } |
| + if (nameNode.token.slowToString() == enclosingClass.name.slowToString()) { |
| + placeholderForType(nameNode, enclosingClass.type); |
| + } |
| + } else { |
| + placeholderForElement(node.name, element); |
| + } |
| + } |
| + |
| + void process(Element element, TreeElements elements) { |
| + if (element.isField()) { |
| + // TODO(smok): In the future make sure we don't process same |
| + // variable list element twice, better merge this with emitter logic. |
| + element = element.variables; |
| + } |
| + currentElement = element; |
| + treeElements = elements; |
| + Node elementNode = element.parseNode(compiler); |
| + if (element is FunctionElement) { |
| + processFunction(element, elementNode); |
| + } |
| + elementNode.accept(this); |
| + } |
| + |
| + Type resolveType(TypeAnnotation typeAnnotation) { |
| + if (treeElements === null) return null; |
| + var result = treeElements.getType(typeAnnotation); |
| + // TODO: Have better type resolution. |
| + if (result === null) { |
| + result = compiler.resolveTypeAnnotation(currentElement, typeAnnotation); |
| + } |
| + return result; |
| + } |
| + |
| + void placeholderForType(Node node, Type type) { |
| + assert(type !== null); |
| + placeholders[node] = new TypePlaceholder(type); |
| + } |
|
Anton Muhin
2012/08/08 08:27:20
nit: blank lines between methods, please
Roman
2012/08/09 05:02:35
Done.
|
| + void placeholderForMethod(Node node, Element method) { |
| + assert(method !== null); |
| + assert(method is FunctionElement || method is VariableElement); |
| + placeholders[node] = new MethodPlaceholder(method); |
| + } |
| + void placeholderForNull(Node node) { |
| + placeholders[node] = new NullPlaceholder(); |
| + } |
| + void placeholderForElement(Node node, Element element) { |
| + assert(element !== null); |
| + placeholders[node] = new ElementPlaceholder(element); |
| + } |
| + |
| + void internalError(String reason, [Node node]) { |
| + compiler.cancel(reason: reason, node: node); |
| + } |
| + |
| + visit(Node node) => (node === null) ? null : node.accept(this); |
| + visitNode(Node node) { node.visitChildren(this); } // We must go deeper. |
|
Anton Muhin
2012/08/08 08:27:20
memegen link? :)
|
| + |
| + visitClassNode(ClassNode node) { |
| + internalError('Should never meet ClassNode', node); |
| + } |
| + |
| + visitSend(Send send) { |
| + new SendVisitor(this, treeElements).visitSend(send); |
| + send.visitChildren(this); |
|
Anton Muhin
2012/08/08 08:27:20
super.visitSend(send)?
Roman
2012/08/09 05:02:35
Done.
|
| + } |
| + |
| + visitTypeAnnotation(TypeAnnotation node) { |
| + final type = compiler.resolveTypeAnnotation(currentElement, node); |
| + if (type is !InterfaceType) return null; |
| + var target = node.typeName; |
| + if (node.typeName is Send) { |
| + final element = treeElements[node]; |
| + if (element !== null) { |
| + final send = node.typeName.asSend(); |
| + final isPrefixed = element.lookupConstructor( |
|
Anton Muhin
2012/08/08 08:27:20
nit: please, rename isPrefixed -> hasPrefix
Roman
2012/08/09 05:02:35
Done.
|
| + send.receiver.source, send.selector.source) === null; |
| + if (!isPrefixed) target = send.receiver; |
| + } |
| + } |
| + placeholderForType(target, type); |
| + visit(node.typeArguments); |
|
Anton Muhin
2012/08/08 08:27:20
super.visitTypeAnnotation(node)?
Roman
2012/08/09 05:02:35
Done.
|
| + } |
| +} |