Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(401)

Unified Diff: frog/leg/resolver.dart

Issue 9243011: Implement named constructors and resolving of redirecting constructors and super-initializers. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Move constructor name creation to lookup function. Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: frog/leg/resolver.dart
diff --git a/frog/leg/resolver.dart b/frog/leg/resolver.dart
index 2fcfbbf6864b04680c7182a8ee5f131d67ab4003..b4ab9728e1a33548e0bcf9874bceedf84b34b13e 100644
--- a/frog/leg/resolver.dart
+++ b/frog/leg/resolver.dart
@@ -42,7 +42,7 @@ class ResolverTask extends CompilerTask {
visitor = new FullResolverVisitor.from(visitor);
if (tree.initializers != null) {
- resolveInitializers(element, tree, visitor);
+ new InitializerResolver(visitor, element).resolveInitializers(tree);
}
visitor.visit(tree.body);
@@ -63,77 +63,190 @@ class ResolverTask extends CompilerTask {
return visitor.mapping;
}
- bool isInitializer(SendSet node) {
+ void resolveType(ClassElement element) {
+ measure(() {
+ ClassNode tree = element.parseNode(compiler, compiler);
+ ClassResolverVisitor visitor = new ClassResolverVisitor(compiler);
+ visitor.visit(tree);
+ });
+ }
+
+ void resolveSignature(FunctionElement element) {
+ measure(() {
+ FunctionExpression node = element.parseNode(compiler, compiler);
+ SignatureResolverVisitor visitor =
+ new SignatureResolverVisitor(compiler, element);
+ visitor.visitFunctionExpression(node);
+ });
+ }
+}
+
+
+class InitializerResolver {
+ final ResolverVisitor visitor;
+ final FunctionElement constructor;
+ final Map<SourceString, Node> initialized;
+ Link<Node> initializers;
+ bool hasSuper;
+
+ bool isSuperConstructorCall(Send node) {
+ return (node.receiver === null &&
+ node.selector.asIdentifier() !== null &&
+ node.selector.asIdentifier().isSuper()) ||
+ (node.receiver !== null &&
+ node.receiver.asIdentifier() !== null &&
+ node.receiver.asIdentifier().isSuper() &&
+ node.selector.asIdentifier() !== null);
+ }
+
+ bool isConstructorRedirect(Send node) {
+ return (node.receiver === null &&
+ node.selector.asIdentifier() !== null &&
+ node.selector.asIdentifier().isThis()) ||
+ (node.receiver !== null &&
+ node.receiver.asIdentifier() !== null &&
+ node.receiver.asIdentifier().isThis() &&
+ node.selector.asIdentifier() !== null);
+ }
+
+ InitializerResolver(this.visitor, this.constructor)
+ : initialized = new Map<SourceString, Node>(), hasSuper = false;
+
+ error(Node node, MessageKind kind, [arguments = const []]) {
+ visitor.error(node, kind, arguments);
+ }
+
+ warning(Node node, MessageKind kind, [arguments = const []]) {
+ visitor.warning(node, kind, arguments);
+ }
+
+ bool isFieldInitializer(SendSet node) {
if (node.selector.asIdentifier() == null) return false;
if (node.receiver == null) return true;
if (node.receiver.asIdentifier() == null) return false;
return node.receiver.asIdentifier().isThis();
}
- SourceString getInitializerFieldName(SendSet node, onError(node)) {
- if (!isInitializer(node)) onError(node);
- return node.selector.asIdentifier().source;
+ void resolveFieldInitializer(SendSet init) {
+ // init is of the form [this.]field = value.
+ final Node selector = init.selector;
+ final SourceString name = selector.asIdentifier().source;
+ // Lookup target field.
+ Element target;
+ if (isFieldInitializer(init)) {
+ final ClassElement classElement = constructor.enclosingElement;
+ target = classElement.lookupLocalMember(name);
+ if (target === null) {
+ error(selector, MessageKind.CANNOT_RESOLVE, [name]);
+ } else if (target.kind != ElementKind.FIELD) {
+ error(selector, MessageKind.NOT_A_FIELD, [name]);
+ } else if (!target.isInstanceMember()) {
+ error(selector, MessageKind.INIT_STATIC_FIELD, [name]);
+ }
+ } else {
+ error(init, MessageKind.INVALID_RECEIVER_IN_INITIALIZER);
+ }
+ visitor.useElement(init, target);
+ // Check for duplicate initializers.
+ if (initialized.containsKey(name)) {
+ error(init, MessageKind.DUPLICATE_INITIALIZER, [name]);
+ warning(initialized[name], MessageKind.ALREADY_INITIALIZED, [name]);
+ }
+ initialized[name] = init;
+ // Resolve initializing value.
+ visitor.visitInStaticContext(init.arguments.head);
+ }
+
+ SourceString getConstructorName(Send node) {
+ if (node.receiver !== null) {
+ return node.selector.asIdentifier().source;
+ } else {
+ return const SourceString('');
+ }
}
- void resolveInitializers(Element element, FunctionExpression node,
- ResolverVisitor visitor) {
- void onError(node) {
- visitor.error(node, MessageKind.INVALID_RECEIVER_IN_INITIALIZER);
+ void resolveSuperOrThis(Send call) {
+ noConstructor(e) {
+ if (e !== null) error(call, MessageKind.NO_CONSTRUCTOR, [e.name, e.kind]);
}
- Map<SourceString, Node> initialized = new Map<SourceString, Node>();
- for (Link<Node> link = node.initializers.nodes;
+
+ ClassElement lookupTarget = constructor.enclosingElement;
+ bool validTarget = true;
+ if (isSuperConstructorCall(call)) {
+ // Check for invalid initializers.
+ if (hasSuper) {
+ error(call, MessageKind.DUPLICATE_SUPER_INITIALIZER);
+ }
+ hasSuper = true;
+ // Calculate correct lookup target and constructor name.
+ if (lookupTarget.name == Types.OBJECT) {
+ error(call, MessageKind.SUPER_INITIALIZER_IN_OBJECT);
+ } else {
+ lookupTarget = lookupTarget.supertype.element;
+ }
+ } else if (isConstructorRedirect(call)) {
+ // Check that there are no other initializers.
+ if (!initializers.tail.isEmpty()) {
+ error(call, MessageKind.REDIRECTING_CTOR_HAS_INITIALIZER);
+ }
+ } else {
+ visitor.error(call, MessageKind.CONSTRUCTOR_CALL_EXPECTED);
+ validTarget = false;
+ }
+
+ if (validTarget) {
+ final SourceString className = lookupTarget.name;
+ final SourceString constructorName = getConstructorName(call);
+ FunctionElement target =
+ lookupTarget.lookupConstructor(className, constructorName,
+ noConstructor);
+ if (target === null && call.arguments.isEmpty()) {
+ target = lookupTarget.getSynthesizedConstructor();
+ }
+ if (target === null) {
+ String name = (constructorName === const SourceString(''))
+ ? className.stringValue
+ : "$className.$constructorName";
+ error(call, MessageKind.CANNOT_RESOLVE_CONSTRUCTOR, [name]);
+ } else {
+ final Compiler compiler = visitor.compiler;
+ // TODO(karlklose): support optional arguments.
+ if (target.parameterCount(compiler) != call.argumentCount()) {
+ error(call, MessageKind.NO_MATCHING_CONSTRUCTOR);
+ }
+ }
+ visitor.useElement(call, target);
+ }
+ // Resolve the arguments of the call.
+ for (Link<Node> arguments = call.arguments;
+ !arguments.isEmpty();
+ arguments = arguments.tail) {
+ visitor.visitInStaticContext(arguments.head);
+ }
+ }
+
+ void resolveInitializers(FunctionExpression node) {
+ if (node.initializers === null) return;
+ initializers = node.initializers.nodes;
+ Compiler compiler = visitor.compiler;
+ for (Link<Node> link = initializers;
!link.isEmpty();
link = link.tail) {
if (link.head.asSendSet() != null) {
- SendSet init = link.head;
- SourceString name = getInitializerFieldName(init, onError);
- ClassElement classElement = element.enclosingElement;
- Element target = classElement.lookupLocalMember(name);
- Node selector = init.selector;
- if (target == null) {
- visitor.error(selector, MessageKind.CANNOT_RESOLVE, [name]);
- } else if (target.kind != ElementKind.FIELD) {
- visitor.error(selector, MessageKind.NOT_A_FIELD, [name]);
- } else if (!target.isInstanceMember()) {
- visitor.error(selector, MessageKind.INIT_STATIC_FIELD, [name]);
- }
- visitor.useElement(init, target);
- if (initialized.containsKey(name)) {
- visitor.error(init, MessageKind.DUPLICATE_INITIALIZER, [name]);
- visitor.warning(initialized[name], MessageKind.ALREADY_INITIALIZED,
- [name]);
- }
- initialized[name] = init;
- Node value = init.arguments.head;
- visitor.visitInStaticContext(value);
+ final SendSet init = link.head.asSendSet();
+ resolveFieldInitializer(init);
} else if (link.head.asSend() !== null) {
- // TODO(karlklose): super(...), this(...).
- compiler.cancel('uniplemented', node:link.head);
+ final Send call = link.head.asSend();
+ resolveSuperOrThis(call);
} else {
- compiler.cancel('internal error: invalid initializer',
- node: link.head);
+ visitor.compiler.cancel('internal error: invalid initializer',
+ node: link.head);
}
}
}
-
- void resolveType(ClassElement element) {
- measure(() {
- ClassNode tree = element.parseNode(compiler, compiler);
- ClassResolverVisitor visitor = new ClassResolverVisitor(compiler);
- visitor.visit(tree);
- });
- }
-
- void resolveSignature(FunctionElement element) {
- measure(() {
- FunctionExpression node = element.parseNode(compiler, compiler);
- SignatureResolverVisitor visitor =
- new SignatureResolverVisitor(compiler, element);
- visitor.visitFunctionExpression(node);
- });
- }
}
+
// TODO(ahe): Frog cannot handle generic types.
class ResolverVisitor extends AbstractVisitor/*<Element>*/ {
final Compiler compiler;
@@ -180,7 +293,7 @@ class ResolverVisitor extends AbstractVisitor/*<Element>*/ {
Element lookup(Node node, SourceString name) {
Element result = context.lookup(name);
if (!inInstanceContext && result != null && result.isInstanceMember()) {
- error(node, MessageKind.NOT_STATIC, [node]);
+ error(node, MessageKind.NO_INSTANCE_AVAILABLE, [node]);
}
return result;
}
@@ -199,7 +312,9 @@ class ResolverVisitor extends AbstractVisitor/*<Element>*/ {
visitIdentifier(Identifier node) {
if (node.isThis()) {
- if (!inInstanceContext) error(node, MessageKind.NO_THIS_IN_STATIC);
+ if (!inInstanceContext) {
+ error(node, MessageKind.NO_INSTANCE_AVAILABLE, [node]);
+ }
return null;
} else if (node.isSuper()) {
if (!inInstanceContext) error(node, MessageKind.NO_SUPER_IN_STATIC);
@@ -214,25 +329,29 @@ class ResolverVisitor extends AbstractVisitor/*<Element>*/ {
}
visitTypeAnnotation(TypeAnnotation node) {
- Identifier name = node.typeName.asIdentifier();
- if (name === null) {
- // TODO(karlklose): In progress.
- cancel(node.typeName, "not implemented");
+ SourceString className;
+ if (node.typeName.asSend() !== null) {
+ // In new and const expressions, the type name can be a Send to
+ // denote named constructors or library prefixes.
+ Send send = node.typeName.asSend();
+ className = send.receiver.asIdentifier().source;
+ } else {
+ className = node.typeName.asIdentifier().source;
}
- if (name.source == const SourceString('var')) return null;
- if (name.source == const SourceString('void')) return null;
- Element element = context.lookup(name.source);
+ if (className == const SourceString('var')) return null;
+ if (className == const SourceString('void')) return null;
+ Element element = context.lookup(className);
if (element === null) {
if (typeRequired) {
- error(node, MessageKind.CANNOT_RESOLVE_TYPE, [name]);
+ error(node, MessageKind.CANNOT_RESOLVE_TYPE, [className]);
} else {
- warning(node, MessageKind.CANNOT_RESOLVE_TYPE, [name]);
+ warning(node, MessageKind.CANNOT_RESOLVE_TYPE, [className]);
}
} else if (element.kind !== ElementKind.CLASS) {
if (typeRequired) {
- error(node, MessageKind.NOT_A_TYPE, [name]);
+ error(node, MessageKind.NOT_A_TYPE, [className]);
} else {
- warning(node, MessageKind.NOT_A_TYPE, [name]);
+ warning(node, MessageKind.NOT_A_TYPE, [className]);
}
} else {
ClassElement cls = element;
@@ -333,14 +452,13 @@ class FullResolverVisitor extends ResolverVisitor {
visitFunctionExpression(FunctionExpression node) {
visit(node.returnType);
+ SourceString name;
if (node.name === null) {
cancel(node, "anonymous functions are not implemented");
}
- if (node.name.asIdentifier() === null) {
- cancel(node.name, "named constructors are not implemented");
- }
+ name = node.name.asIdentifier().source;
FunctionElement enclosingElement = new FunctionElement.node(
- node, ElementKind.FUNCTION, null, context.element);
+ name, node, ElementKind.FUNCTION, null, context.element);
defineElement(node, enclosingElement);
context = new MethodScope(context, enclosingElement);
@@ -517,22 +635,39 @@ class FullResolverVisitor extends ResolverVisitor {
visit(node.send.argumentsNode);
+ SourceString constructorName;
+ Node typeName = node.send.selector.asTypeAnnotation().typeName;
+ if (typeName.asSend() !== null) {
+ Identifier receiver = typeName.asSend().receiver.asIdentifier();
+ Identifier selector = typeName.asSend().selector.asIdentifier();
+ SourceString className = receiver.source;
+ SourceString name = selector.source;
+ constructorName = new SourceString('$className.$name');
+ } else {
+ constructorName = typeName.asIdentifier().source;
+ }
ClassElement cls = resolveTypeRequired(node.send.selector);
Element constructor = null;
if (cls !== null) {
- // TODO(ngeoffray): set constructor-name correctly.
- SourceString name = cls.name;
- constructor = cls.resolve(compiler).lookupConstructor(name);
- if (name == cls.name
+ constructor = cls.resolve(compiler).lookupConstructor(constructorName);
+ if (constructorName == cls.name
&& constructor === null
&& node.send.argumentsNode.isEmpty()) {
constructor = cls.getSynthesizedConstructor();
}
if (constructor === null) {
- error(node, MessageKind.CANNOT_FIND_CONSTRUCTOR, [node]);
+ error(node.send, MessageKind.CANNOT_FIND_CONSTRUCTOR, [node.send]);
+ } else {
+ FunctionElement function = constructor;
+ // TODO(karlklose): handle optional arguments.
+ if (node.send.argumentCount() != function.parameterCount(compiler)) {
+ error(node.send, MessageKind.CANNOT_FIND_CONSTRUCTOR, [node.send]);
+ }
}
+ } else {
+ Node selector = node.send.selector;
+ error(selector, MessageKind.CANNOT_RESOLVE_TYPE, [selector]);
}
-
useElement(node.send, constructor);
return null;
}

Powered by Google App Engine
This is Rietveld 408576698