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

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: Rename field. 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 fa6e2108d39c5c9e333e46dfc27e65b033c981db..6307ef5782e52c3d7623136f7f41ecd315be6a4c 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);
@@ -64,77 +64,174 @@ class ResolverTask extends CompilerTask {
return visitor.mapping;
}
- bool isInitializer(SendSet node) {
+ void resolveType(ClassElement element) {
+ measure(() {
+ ClassNode tree = element.node;
+ ClassResolverVisitor visitor = new ClassResolverVisitor(compiler);
+ visitor.visit(tree);
+ });
+ }
+
+ void resolveSignature(FunctionElement element) {
+ measure(() {
+ FunctionExpression node = element.node;
+ SignatureResolverVisitor visitor =
+ new SignatureResolverVisitor(compiler, element);
+ visitor.visitFunctionExpression(node);
+ });
+ }
+}
+
+
+class InitializerResolver {
+ final ResolverVisitor visitor;
+ final FunctionElement constructor;
+ Map<SourceString, Node> initialized;
+ Node initializerOrSuper;
+ bool hasSuper;
+
+ InitializerResolver(this.visitor, this.constructor)
+ : initialized = new Map<SourceString, Node>(), hasSuper = false;
+
+ Universe get universe() => visitor.compiler.universe;
+
+ 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)) {
+ if (initializerOrSuper == null) initializerOrSuper = init;
floitsch 2012/01/18 15:22:14 initializerOrSuper is unconditionally reassigned b
karlklose 2012/01/18 16:36:09 Done, moved.
+ 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);
+ initializerOrSuper = init;
+ }
+
+ SourceString getConstructorName(ClassElement cls, Send node) {
+ SourceString constructor = node.selector.asIdentifier().source;
+ if (node.receiver !== null) {
+ return new SourceString('${cls.name}.$constructor');
+ } else {
+ return cls.name;
+ }
}
- void resolveInitializers(Element element, FunctionExpression node,
- ResolverVisitor visitor) {
- void onError(node) {
- visitor.error(node, MessageKind.INVALID_RECEIVER_IN_INITIALIZER);
+ void resolveSuperOrThis(Send call, Node next) {
+ noConstructor(e) {
+ if (e !== null) error(call, MessageKind.NO_CONSTRUCTOR, [e.name, e.kind]);
+ }
+ ClassElement lookupTarget = constructor.enclosingElement;
floitsch 2012/01/18 15:22:14 new line after nested function.
karlklose 2012/01/18 16:36:09 Done.
+ if (call.isSuperConstructorCall) {
+ // Check for invalid initializers.
+ if (hasSuper) {
+ error(call, MessageKind.DUPLICATE_SUPER_INITIALIZER);
+ }
+ if (initializerOrSuper == null) initializerOrSuper = call;
+ hasSuper = true;
+ // Calculate correct lookup target and constructor name.
+ if (constructor.name === Types.OBJECT) {
+ error(call, MessageKind.SUPER_INITIALIZER_IN_OBJECT);
+ } else {
+ lookupTarget = lookupTarget.supertype.element;
+ }
+ } else if (call.isConstructorRedirect) {
+ // Check that there are no other initializers.
+ if (initializerOrSuper !== null || next !== null) {
+ Node diagnosticNode =
+ initializerOrSuper !== null ? initializerOrSuper
+ : next;
+ error(diagnosticNode,
+ MessageKind.REDIRECTING_CTOR_HAS_INITIALIZER);
+ }
+ } else {
+ visitor.error(call, MessageKind.CONSTRUCTOR_CALL_EXPECTED);
+ }
+
+ final SourceString name = getConstructorName(lookupTarget, call);
+ FunctionElement target =
+ lookupTarget.lookupConstructor(name, noConstructor);
+ if (target === null && call.arguments.isEmpty()) {
+ target = lookupTarget.getSynthesizedConstructor();
floitsch 2012/01/18 15:22:14 what if there is no synthesized constructor? The n
karlklose 2012/01/18 16:36:09 Done.
+ } else if (target === null) {
+ error(call, MessageKind.CANNOT_RESOLVE, ["constructor $name"]);
+ } else {
+ final Compiler compiler = visitor.compiler;
+ final FunctionExpression targetNode =
+ target.parseNode(compiler, compiler);
+ final int parameters = targetNode.parameterCount();
floitsch 2012/01/18 15:22:14 no need to create these intermediate variables. pa
karlklose 2012/01/18 16:36:09 Done.
+ final int arguments = call.argumentCount();
+ // TODO(karlklose): support optional arguments.
+ if (parameters != arguments) {
+ error(call, MessageKind.NO_MATCHING_CONSTRUCTOR);
+ }
}
- Map<SourceString, Node> initialized = new Map<SourceString, Node>();
+ visitor.compiler.enqueue(new WorkItem.toCompile(target));
+ 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;
+ Compiler compiler = visitor.compiler;
+ // TODO(karlklose): implement initializer parameters.
for (Link<Node> link = node.initializers.nodes;
!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, link.tail.isEmpty() ? null : link.tail.head);
} 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.node;
- ClassResolverVisitor visitor = new ClassResolverVisitor(compiler);
- visitor.visit(tree);
- });
- }
-
- void resolveSignature(FunctionElement element) {
- measure(() {
- FunctionExpression node = element.node;
- SignatureResolverVisitor visitor =
- new SignatureResolverVisitor(compiler, element);
- visitor.visitFunctionExpression(node);
- });
- }
}
+
// TODO(ahe): Frog cannot handle generic types.
class ResolverVisitor extends AbstractVisitor/*<Element>*/ {
final Compiler compiler;
@@ -181,7 +278,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,8 +296,10 @@ class ResolverVisitor extends AbstractVisitor/*<Element>*/ {
}
visitIdentifier(Identifier node) {
- if (node.isThis()) {
- if (!inInstanceContext) error(node, MessageKind.NO_THIS_IN_STATIC);
+ if (node.isThis() || node.isSuper()) {
+ if (!inInstanceContext) {
+ error(node, MessageKind.NO_INSTANCE_AVAILABLE, [node]);
+ }
return null;
} else if (node.isSuper()) {
if (!inInstanceContext) error(node, MessageKind.NO_SUPER_IN_STATIC);
@@ -215,25 +314,27 @@ 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) {
floitsch 2012/01/18 15:22:14 add comment when this happen (for 'new' and 'const
karlklose 2012/01/18 16:36:09 Done.
+ 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;
@@ -334,14 +435,17 @@ 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");
+ } else if (node.name.asSend() != null) {
+ Identifier cls = node.asSend().receiver.asIdentifier();
+ Identifier constructor = node.asSend().selector.asIdentifier();
floitsch 2012/01/18 15:22:14 something missing here?
karlklose 2012/01/18 16:36:09 Done.
+ } else {
+ 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);
@@ -518,22 +622,41 @@ 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 {
+ FunctionExpression fun = constructor.parseNode(compiler, compiler);
+ int argumentCount = node.send.argumentCount();
+ int parameterCount = fun.parameterCount();
floitsch 2012/01/18 15:22:14 ditto. no need to have these intermediate variable
karlklose 2012/01/18 16:36:09 Done.
+ // TODO(karlklose): handle optional arguments.
+ if (argumentCount != parameterCount) {
+ 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