Chromium Code Reviews| Index: frog/leg/resolver.dart |
| diff --git a/frog/leg/resolver.dart b/frog/leg/resolver.dart |
| index a5adba36850111b4eb1e4fd0a2c45037f929e74f..58ec98f6475695e30ef5e5a933dcde8c3c498f58 100644 |
| --- a/frog/leg/resolver.dart |
| +++ b/frog/leg/resolver.dart |
| @@ -68,7 +68,27 @@ class ResolverTask extends CompilerTask { |
| visitor.setupFunction(tree, element); |
| if (tree.initializers != null) { |
|
floitsch
2012/02/14 16:38:02
maybe verify in here that we have a constructor.
karlklose
2012/02/15 13:10:35
Done.
|
| - new InitializerResolver(visitor, element).resolveInitializers(tree); |
| + InitializerResolver resolver = new InitializerResolver(visitor); |
| + FunctionElement redirection = resolver.resolveInitializers(element, tree); |
| + Set<FunctionElement> seen; // Initialized lazily. |
| + while (redirection !== null) { |
| + if (seen === null) { |
| + seen = new Set<FunctionElement>(); |
| + seen.add(element); |
| + } |
| + if (seen.contains(redirection)) { |
| + visitor.error(tree, MessageKind.REDIRECTING_CONSTRUCTOR_CYCLE); |
| + break; |
| + } |
| + seen.add(redirection); |
| + FunctionExpression functionNode = redirection.parseNode(compiler); |
| + if (functionNode !== null) { |
| + redirection = resolver.resolveRedirection(redirection, functionNode); |
| + } else { |
| + // A synthetic constructor does not have a node. |
| + redirection = null; |
| + } |
| + } |
| } |
| visitor.visit(tree.body); |
| @@ -140,7 +160,6 @@ class ResolverTask extends CompilerTask { |
| [classElement.name]); |
| classElement.allSupertypes = const EmptyLink<Type>(); |
| } else if (supertype != null) { |
| - Type supertype = classElement.supertype; |
| seen.add(classElement); |
| Link<Type> superSupertypes = |
| getOrCalculateAllSupertypes(supertype.element, seen); |
| @@ -161,19 +180,18 @@ class ResolverTask extends CompilerTask { |
| } |
| error(Node node, MessageKind kind, [arguments = const []]) { |
| - ResolutionError error = new ResolutionError(kind, arguments); |
| + ResolutionError message = new ResolutionError(kind, arguments); |
| compiler.reportError(node, error); |
|
floitsch
2012/02/14 16:38:02
message?
karlklose
2012/02/15 13:10:35
Done.
|
| } |
| } |
| class InitializerResolver { |
| final ResolverVisitor visitor; |
| - final FunctionElement constructor; |
| final Map<SourceString, Node> initialized; |
| Link<Node> initializers; |
| bool hasSuper; |
| - InitializerResolver(this.visitor, this.constructor) |
| + InitializerResolver(this.visitor) |
| : initialized = new Map<SourceString, Node>(), hasSuper = false; |
| error(Node node, MessageKind kind, [arguments = const []]) { |
| @@ -191,7 +209,7 @@ class InitializerResolver { |
| return node.receiver.asIdentifier().isThis(); |
| } |
| - void resolveFieldInitializer(SendSet init) { |
| + void resolveFieldInitializer(FunctionElement constructor, SendSet init) { |
| // init is of the form [this.]field = value. |
| final Node selector = init.selector; |
| final SourceString name = selector.asIdentifier().source; |
| @@ -229,13 +247,16 @@ class InitializerResolver { |
| } |
| } |
| - void resolveSuperOrThis(Send call) { |
| + Element resolveSuperOrThis(FunctionElement constructor, |
| + FunctionExpression functionNode, |
| + Send call) { |
| noConstructor(e) { |
| if (e !== null) error(call, MessageKind.NO_CONSTRUCTOR, [e.name, e.kind]); |
| } |
| ClassElement lookupTarget = constructor.enclosingElement; |
| bool validTarget = true; |
| + FunctionElement result; |
| if (Initializers.isSuperConstructorCall(call)) { |
| // Check for invalid initializers. |
| if (hasSuper) { |
| @@ -249,9 +270,13 @@ class InitializerResolver { |
| lookupTarget = lookupTarget.supertype.element; |
| } |
| } else if (Initializers.isConstructorRedirect(call)) { |
| + // Check that there is no body (Language specification 7.5.1). |
| + if (functionNode.hasBody()) { |
| + error(functionNode, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_BODY); |
| + } |
| // Check that there are no other initializers. |
| if (!initializers.tail.isEmpty()) { |
| - error(call, MessageKind.REDIRECTING_CTOR_HAS_INITIALIZER); |
| + error(call, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER); |
| } |
| } else { |
| visitor.error(call, MessageKind.CONSTRUCTOR_CALL_EXPECTED); |
| @@ -261,13 +286,12 @@ class InitializerResolver { |
| if (validTarget) { |
| final SourceString className = lookupTarget.name; |
| final SourceString constructorName = getConstructorName(call); |
| - FunctionElement target = |
| - lookupTarget.lookupConstructor(className, constructorName, |
| + result = lookupTarget.lookupConstructor(className, constructorName, |
| noConstructor); |
|
floitsch
2012/02/14 16:38:02
indendation
karlklose
2012/02/15 13:10:35
Done.
|
| - if (target === null && call.arguments.isEmpty()) { |
| - target = lookupTarget.getSynthesizedConstructor(); |
| + if (result === null && call.arguments.isEmpty()) { |
| + result = lookupTarget.getSynthesizedConstructor(); |
| } |
| - if (target === null) { |
| + if (result === null) { |
| String name = (constructorName === const SourceString('')) |
| ? className.stringValue |
| : "$className.$constructorName"; |
| @@ -275,11 +299,11 @@ class InitializerResolver { |
| } else { |
| final Compiler compiler = visitor.compiler; |
| // TODO(karlklose): support optional arguments. |
| - if (target.parameterCount(compiler) != call.argumentCount()) { |
| + if (result.parameterCount(compiler) != call.argumentCount()) { |
| error(call, MessageKind.NO_MATCHING_CONSTRUCTOR); |
| } |
| } |
| - visitor.useElement(call, target); |
| + visitor.useElement(call, result); |
| } |
| // Resolve the arguments of the call. |
| for (Link<Node> arguments = call.arguments; |
| @@ -287,30 +311,47 @@ class InitializerResolver { |
| arguments = arguments.tail) { |
| visitor.visitInStaticContext(arguments.head); |
| } |
| + return result; |
| } |
| - void resolveInitializers(FunctionExpression node) { |
| - if (node.initializers === null) return; |
| - initializers = node.initializers.nodes; |
| - Compiler compiler = visitor.compiler; |
| + FunctionElement resolveRedirection(FunctionElement constructor, |
| + FunctionExpression functionNode) { |
| + if (functionNode.initializers === null) return null; |
| + Link<Node> link = functionNode.initializers.nodes; |
| + if (!link.isEmpty() && Initializers.isConstructorRedirect(link.head)) { |
| + return resolveSuperOrThis(constructor, functionNode, link.head); |
| + } |
| + return null; |
| + } |
| + |
| + /** |
| + * Resolve all initializers of this constructor. In the case of a redirecting |
| + * constructor, the resolved constructor's function element is returned. |
| + */ |
| + FunctionElement resolveInitializers(FunctionElement constructor, |
| + FunctionExpression functionNode) { |
| + if (functionNode.initializers === null) return null; |
| + initializers = functionNode.initializers.nodes; |
| + FunctionElement result; |
| for (Link<Node> link = initializers; |
| !link.isEmpty(); |
| link = link.tail) { |
| if (link.head.asSendSet() != null) { |
| final SendSet init = link.head.asSendSet(); |
| - resolveFieldInitializer(init); |
| + resolveFieldInitializer(constructor, init); |
| } else if (link.head.asSend() !== null) { |
| final Send call = link.head.asSend(); |
| - resolveSuperOrThis(call); |
| + result = resolveSuperOrThis(constructor, functionNode, call); |
| } else { |
| visitor.compiler.cancel('internal error: invalid initializer', |
|
floitsch
2012/02/14 16:38:02
This is not an internal error. The parser accepts
karlklose
2012/02/15 13:10:35
Done.
|
| node: link.head); |
| } |
| } |
| + return result; |
| } |
| } |
| -class CommonResolverVisitor<R> extends AbstractVisitor<Element> { |
| +class CommonResolverVisitor<R> extends AbstractVisitor<R> { |
| final Compiler compiler; |
| CommonResolverVisitor(Compiler this.compiler); |
| @@ -323,13 +364,13 @@ class CommonResolverVisitor<R> extends AbstractVisitor<Element> { |
| R visit(Node node) => (node == null) ? null : node.accept(this); |
| void error(Node node, MessageKind kind, [arguments = const []]) { |
| - ResolutionError error = new ResolutionError(kind, arguments); |
| - compiler.reportError(node, error); |
| + ResolutionError message = new ResolutionError(kind, arguments); |
| + compiler.reportError(node, message); |
| } |
| void warning(Node node, MessageKind kind, [arguments = const []]) { |
| - ResolutionWarning warning = new ResolutionWarning(kind, arguments); |
| - compiler.reportWarning(node, warning); |
| + ResolutionWarning message = new ResolutionWarning(kind, arguments); |
| + compiler.reportWarning(node, message); |
| } |
| void cancel(Node node, String message) { |