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

Unified Diff: frog/leg/resolver.dart

Issue 9873021: Move frog/leg to lib/compiler/implementation. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 9 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
« no previous file with comments | « frog/leg/operations.dart ('k') | frog/leg/scanner/array_based_scanner.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: frog/leg/resolver.dart
===================================================================
--- frog/leg/resolver.dart (revision 5925)
+++ frog/leg/resolver.dart (working copy)
@@ -1,1800 +0,0 @@
-// 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.
-
-interface TreeElements {
- Element operator[](Node node);
- Selector getSelector(Send send);
-}
-
-class TreeElementMapping implements TreeElements {
- Map<Node, Element> map;
- Map<Send, Selector> selectors;
- TreeElementMapping()
- : map = new LinkedHashMap<Node, Element>(),
- selectors = new LinkedHashMap<Send, Selector>();
-
- operator []=(Node node, Element element) => map[node] = element;
- operator [](Node node) => map[node];
- void remove(Node node) { map.remove(node); }
-
- void setSelector(Send send, Selector selector) {
- selectors[send] = selector;
- }
-
- Selector getSelector(Send send) => selectors[send];
-}
-
-class ResolverTask extends CompilerTask {
- Queue<ClassElement> toResolve;
-
- // Caches the elements of analyzed constructors to make them available
- // for inlining in later tasks.
- Map<FunctionElement, TreeElements> constructorElements;
-
- ResolverTask(Compiler compiler)
- : super(compiler), toResolve = new Queue<ClassElement>(),
- constructorElements = new Map<FunctionElement, TreeElements>();
-
- String get name() => 'Resolver';
-
- TreeElements resolve(Element element) {
- return measure(() {
- switch (element.kind) {
- case ElementKind.GENERATIVE_CONSTRUCTOR:
- case ElementKind.FUNCTION:
- case ElementKind.GETTER:
- case ElementKind.SETTER:
- return resolveMethodElement(element);
-
- case ElementKind.FIELD:
- return resolveField(element);
-
- case ElementKind.PARAMETER:
- case ElementKind.FIELD_PARAMETER:
- return resolveParameter(element);
-
- default:
- compiler.unimplemented(
- "resolver", node: element.parseNode(compiler));
- }
- });
- }
-
- SourceString getConstructorName(Send node) {
- if (node.receiver !== null) {
- return node.selector.asIdentifier().source;
- } else {
- return const SourceString('');
- }
- }
-
- FunctionElement lookupConstructor(ClassElement classElement, Send send,
- [noConstructor(Element)]) {
- final SourceString constructorName = getConstructorName(send);
- final SourceString className = classElement.name;
- return classElement.lookupConstructor(className,
- constructorName,
- noConstructor);
- }
-
- FunctionElement resolveConstructorRedirection(FunctionElement constructor) {
- FunctionExpression node = constructor.parseNode(compiler);
- // A synthetic constructor does not have a node.
- if (node === null) return null;
- if (node.initializers === null) return null;
- Link<Node> initializers = node.initializers.nodes;
- if (!initializers.isEmpty() &&
- Initializers.isConstructorRedirect(initializers.head)) {
- return lookupConstructor(constructor.enclosingElement, initializers.head);
- }
- return null;
- }
-
- void resolveRedirectingConstructor(InitializerResolver resolver,
- Node node,
- FunctionElement constructor,
- FunctionElement redirection) {
- Set<FunctionElement> seen = new Set<FunctionElement>();
- seen.add(constructor);
- while (redirection !== null) {
- if (seen.contains(redirection)) {
- resolver.visitor.error(node, MessageKind.REDIRECTING_CONSTRUCTOR_CYCLE);
- return;
- }
- seen.add(redirection);
- redirection = resolveConstructorRedirection(redirection);
- }
- }
-
- TreeElements resolveMethodElement(FunctionElement element) {
- return compiler.withCurrentElement(element, () {
- bool isConstructor = element.kind === ElementKind.GENERATIVE_CONSTRUCTOR;
- if (constructorElements.containsKey(element)) {
- assert(isConstructor);
- TreeElements elements = constructorElements[element];
- if (elements !== null) return elements;
- }
- FunctionExpression tree = element.parseNode(compiler);
- if (isConstructor) {
- resolveConstructorImplementation(element, tree);
- }
- ResolverVisitor visitor = new ResolverVisitor(compiler, element);
- visitor.useElement(tree, element);
- visitor.setupFunction(tree, element);
-
- if (tree.initializers != null) {
- if (!isConstructor) {
- error(tree, MessageKind.FUNCTION_WITH_INITIALIZER);
- }
- InitializerResolver resolver = new InitializerResolver(visitor);
- FunctionElement redirection =
- resolver.resolveInitializers(element, tree);
- if (redirection !== null) {
- resolveRedirectingConstructor(resolver, tree, element, redirection);
- }
- }
- visitor.visit(tree.body);
-
- // Resolve the type annotations encountered in the method.
- while (!toResolve.isEmpty()) {
- ClassElement classElement = toResolve.removeFirst();
- classElement.ensureResolved(compiler);
- }
- if (isConstructor) {
- constructorElements[element] = visitor.mapping;
- }
- return visitor.mapping;
- });
- }
-
- void resolveConstructorImplementation(FunctionElement constructor,
- FunctionExpression node) {
- assert(constructor.defaultImplementation === constructor);
- ClassElement intrface = constructor.enclosingElement;
- if (!intrface.isInterface()) return;
- Type defaultType = intrface.defaultClass;
- if (defaultType === null) {
- error(node, MessageKind.NO_DEFAULT_CLASS, [intrface.name]);
- }
- ClassElement defaultClass = defaultType.element;
- defaultClass.ensureResolved(compiler);
- if (defaultClass.isInterface()) {
- error(node, MessageKind.CANNOT_INSTANTIATE_INTERFACE,
- [defaultClass.name]);
- }
- // We have now established the following:
- // [intrface] is an interface, let's say "MyInterface".
- // [defaultClass] is a class, let's say "MyClass".
-
- // First look up the constructor named "MyInterface.name".
- constructor.defaultImplementation =
- defaultClass.lookupConstructor(constructor.name);
-
- // If that fails, try looking up "MyClass.name".
- if (constructor.defaultImplementation === null) {
- SourceString name =
- new SourceString(constructor.name.slowToString().replaceFirst(
- intrface.name.slowToString(),
- defaultClass.name.slowToString()));
- constructor.defaultImplementation = defaultClass.lookupConstructor(name);
-
- if (constructor.defaultImplementation === null) {
- // We failed find a constrcutor named either
- // "MyInterface.name" or "MyClass.name".
- error(node, MessageKind.CANNOT_FIND_CONSTRUCTOR2,
- [constructor.name, name]);
- }
- }
- }
-
- TreeElements resolveField(Element element) {
- Node tree = element.parseNode(compiler);
- ResolverVisitor visitor = new ResolverVisitor(compiler, element);
- initializerDo(tree, visitor.visit);
- return visitor.mapping;
- }
-
- TreeElements resolveParameter(Element element) {
- Node tree = element.parseNode(compiler);
- ResolverVisitor visitor =
- new ResolverVisitor(compiler, element.enclosingElement);
- initializerDo(tree, visitor.visit);
- return visitor.mapping;
- }
-
- Type resolveType(ClassElement element) {
- if (element.isResolved) return element.type;
- return measure(() {
- ClassNode tree = element.parseNode(compiler);
- ClassResolverVisitor visitor =
- new ClassResolverVisitor(compiler, element.getLibrary(), element);
- visitor.visit(tree);
- element.isResolved = true;
- return element.type;
- });
- }
-
- FunctionParameters resolveSignature(FunctionElement element) {
- return measure(() => SignatureResolver.analyze(compiler, element));
- }
-
- error(Node node, MessageKind kind, [arguments = const []]) {
- ResolutionError message = new ResolutionError(kind, arguments);
- compiler.reportError(node, message);
- }
-}
-
-class InitializerResolver {
- final ResolverVisitor visitor;
- final Map<SourceString, Node> initialized;
- Link<Node> initializers;
- bool hasSuper;
-
- InitializerResolver(this.visitor)
- : 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();
- }
-
- 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;
- // 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);
- }
-
- 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) {
- 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 (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_CONSTRUCTOR_HAS_INITIALIZER);
- }
- } else {
- visitor.error(call, MessageKind.CONSTRUCTOR_CALL_EXPECTED);
- validTarget = false;
- }
-
- if (validTarget) {
- // Resolve the arguments, and make sure the call gets a selector
- // by calling handleArguments.
- visitor.inStaticContext( () => visitor.handleArguments(call) );
- // Lookup constructor and try to match it to the selector.
- ResolverTask resolver = visitor.compiler.resolver;
- result = resolver.lookupConstructor(lookupTarget, call);
- if (result === null) {
- SourceString constructorName = resolver.getConstructorName(call);
- String className = lookupTarget.name.slowToString();
- String name = (constructorName === const SourceString(''))
- ? className
- : "$className.${constructorName.slowToString()}";
- error(call, MessageKind.CANNOT_RESOLVE_CONSTRUCTOR, [name]);
- } else {
- final Compiler compiler = visitor.compiler;
- Selector selector = visitor.mapping.getSelector(call);
- FunctionParameters parameters = result.computeParameters(compiler);
- // TODO(karlklose): support optional arguments.
- if (!selector.applies(parameters)) {
- error(call, MessageKind.NO_MATCHING_CONSTRUCTOR);
- }
- }
- visitor.useElement(call, result);
- }
- return result;
- }
-
- 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(constructor, init);
- } else if (link.head.asSend() !== null) {
- final Send call = link.head.asSend();
- result = resolveSuperOrThis(constructor, functionNode, call);
- } else {
- error(link.head, MessageKind.INVALID_INITIALIZER);
- }
- }
- return result;
- }
-}
-
-class CommonResolverVisitor<R> extends AbstractVisitor<R> {
- final Compiler compiler;
-
- CommonResolverVisitor(Compiler this.compiler);
-
- R visitNode(Node node) {
- cancel(node, 'internal error');
- }
-
- R visitEmptyStatement(Node node) => null;
-
- /** Convenience method for visiting nodes that may be null. */
- R visit(Node node) => (node == null) ? null : node.accept(this);
-
- void error(Node node, MessageKind kind, [arguments = const []]) {
- ResolutionError message = new ResolutionError(kind, arguments);
- compiler.reportError(node, message);
- }
-
- void warning(Node node, MessageKind kind, [arguments = const []]) {
- ResolutionWarning message = new ResolutionWarning(kind, arguments);
- compiler.reportWarning(node, message);
- }
-
- void cancel(Node node, String message) {
- compiler.cancel(message, node: node);
- }
-
- void internalError(Node node, String message) {
- compiler.internalError(message, node: node);
- }
-
- void unimplemented(Node node, String message) {
- compiler.unimplemented(message, node: node);
- }
-}
-
-interface LabelScope {
- LabelScope get outer();
- LabelElement lookup(String label);
-}
-
-class LabeledStatementLabelScope implements LabelScope {
- final LabelScope outer;
- final LabelElement label;
- LabeledStatementLabelScope(this.outer, this.label);
- LabelElement lookup(String labelName) {
- if (this.label.labelName == labelName) return label;
- return outer.lookup(labelName);
- }
-}
-
-class SwitchLabelScope implements LabelScope {
- final LabelScope outer;
- final Map<String, LabelElement> caseLabels;
-
- SwitchLabelScope(this.outer, this.caseLabels);
-
- LabelElement lookup(String labelName) {
- LabelElement result = caseLabels[labelName];
- if (result !== null) return result;
- return outer.lookup(labelName);
- }
-}
-
-class EmptyLabelScope implements LabelScope {
- const EmptyLabelScope();
- LabelElement lookup(String label) => null;
- LabelScope get outer() {
- throw 'internal error: empty label scope has no outer';
- }
-}
-
-class StatementScope {
- LabelScope labels;
- Link<TargetElement> breakTargetStack;
- Link<TargetElement> continueTargetStack;
- // Used to provide different numbers to statements if one is inside the other.
- // Can be used to make otherwise duplicate labels unique.
- int nestingLevel = 0;
-
- StatementScope()
- : labels = const EmptyLabelScope(),
- breakTargetStack = const EmptyLink<TargetElement>(),
- continueTargetStack = const EmptyLink<TargetElement>();
-
- LabelElement lookupLabel(String label) {
- return labels.lookup(label);
- }
- TargetElement currentBreakTarget() =>
- breakTargetStack.isEmpty() ? null : breakTargetStack.head;
-
- TargetElement currentContinueTarget() =>
- continueTargetStack.isEmpty() ? null : continueTargetStack.head;
-
- void enterLabelScope(LabelElement element) {
- labels = new LabeledStatementLabelScope(labels, element);
- nestingLevel++;
- }
-
- void exitLabelScope() {
- nestingLevel--;
- labels = labels.outer;
- }
-
- void enterLoop(TargetElement element) {
- breakTargetStack = breakTargetStack.prepend(element);
- continueTargetStack = continueTargetStack.prepend(element);
- nestingLevel++;
- }
-
- void exitLoop() {
- nestingLevel--;
- breakTargetStack = breakTargetStack.tail;
- continueTargetStack = continueTargetStack.tail;
- }
-
- void enterSwitch(TargetElement breakElement,
- Map<String, LabelElement> continueElements) {
- breakTargetStack = breakTargetStack.prepend(breakElement);
- labels = new SwitchLabelScope(labels, continueElements);
- nestingLevel++;
- }
-
- void exitSwitch() {
- nestingLevel--;
- breakTargetStack = breakTargetStack.tail;
- labels = labels.outer;
- }
-}
-
-class ResolverVisitor extends CommonResolverVisitor<Element> {
- final TreeElementMapping mapping;
- final Element enclosingElement;
- bool inInstanceContext;
- Scope context;
- ClassElement currentClass;
- bool typeRequired = false;
- StatementScope statementScope;
- int allowedCategory = ElementCategory.VARIABLE | ElementCategory.FUNCTION;
-
- ResolverVisitor(Compiler compiler, Element element)
- : this.mapping = new TreeElementMapping(),
- this.enclosingElement = element,
- inInstanceContext = element.isInstanceMember()
- || element.isGenerativeConstructor(),
- this.context = element.isMember()
- ? new ClassScope(element.enclosingElement, element.getLibrary())
- : new TopScope(element.getLibrary()),
- this.currentClass = element.isMember() ? element.enclosingElement : null,
- this.statementScope = new StatementScope(),
- super(compiler);
-
- Element lookup(Node node, SourceString name) {
- Element result = context.lookup(name);
- if (!inInstanceContext && result != null && result.isInstanceMember()) {
- error(node, MessageKind.NO_INSTANCE_AVAILABLE, [node]);
- }
- return result;
- }
-
- // Create, or reuse an already created, statement element for a statement.
- TargetElement getOrCreateTargetElement(Node statement) {
- TargetElement element = mapping[statement];
- if (element === null) {
- element = new TargetElement(statement,
- statementScope.nestingLevel,
- enclosingElement);
- mapping[statement] = element;
- }
- return element;
- }
-
- inStaticContext(action()) {
- bool wasInstanceContext = inInstanceContext;
- inInstanceContext = false;
- var result = action();
- inInstanceContext = wasInstanceContext;
- return result;
- }
-
- visitInStaticContext(Node node) {
- inStaticContext(() => visit(node));
- }
-
- Element visitIdentifier(Identifier node) {
- if (node.isThis()) {
- if (!inInstanceContext) {
- error(node, MessageKind.NO_INSTANCE_AVAILABLE, [node]);
- }
- return null;
- } else if (node.isSuper()) {
- if (!inInstanceContext) error(node, MessageKind.NO_SUPER_IN_STATIC);
- if ((ElementCategory.SUPER & allowedCategory) == 0) {
- error(node, MessageKind.INVALID_USE_OF_SUPER);
- }
- return null;
- } else {
- Element element = lookup(node, node.source);
- if (element === null) {
- if (!inInstanceContext) error(node, MessageKind.CANNOT_RESOLVE, [node]);
- } else {
- if ((element.kind.category & allowedCategory) == 0) {
- // TODO(ahe): Improve error message. Need UX input.
- error(node, MessageKind.GENERIC, ["is not an expression $element"]);
- }
- }
- return useElement(node, element);
- }
- }
-
- visitTypeAnnotation(TypeAnnotation node) {
- Send send = node.typeName.asSend();
- Element element;
- if (send !== null) {
- if (typeRequired) {
- element = resolveSend(send);
- } else {
- // Not calling resolveSend as it will emit an error instead of
- // a warning if the type is bogus.
- // TODO(ahe): Change resolveSend so it can emit a warning when needed.
- return null;
- }
- } else {
- element = context.lookup(node.typeName.asIdentifier().source);
- }
- if (element === null) {
- if (typeRequired) {
- error(node, MessageKind.CANNOT_RESOLVE_TYPE, [node.typeName]);
- } else {
- warning(node, MessageKind.CANNOT_RESOLVE_TYPE, [node.typeName]);
- }
- } else if (!element.impliesType()) {
- if (typeRequired) {
- error(node, MessageKind.NOT_A_TYPE, [node.typeName]);
- } else {
- warning(node, MessageKind.NOT_A_TYPE, [node.typeName]);
- }
- } else {
- if (element.isClass()) {
- // TODO(ngeoffray): Should we also resolve typedef?
- ClassElement cls = element;
- compiler.resolver.toResolve.add(element);
- }
- // TODO(ahe): This should be a Type.
- useElement(node, element);
- }
- return element;
- }
-
- Element defineElement(Node node, Element element,
- [bool doAddToScope = true]) {
- compiler.ensure(element !== null);
- mapping[node] = element;
- if (doAddToScope) {
- Element existing = context.add(element);
- if (existing != element) {
- error(node, MessageKind.DUPLICATE_DEFINITION, [node]);
- }
- }
- return element;
- }
-
- Element useElement(Node node, Element element) {
- if (element === null) return null;
- return mapping[node] = element;
- }
-
- void setupFunction(FunctionExpression node, FunctionElement function) {
- context = new MethodScope(context, function);
- // Put the parameters in scope.
- FunctionParameters functionParameters =
- function.computeParameters(compiler);
- Link<Node> parameterNodes = node.parameters.nodes;
- functionParameters.forEachParameter((Element element) {
- if (element == functionParameters.optionalParameters.head) {
- NodeList nodes = parameterNodes.head;
- parameterNodes = nodes.nodes;
- }
- VariableDefinitions variableDefinitions = parameterNodes.head;
- Node parameterNode = variableDefinitions.definitions.nodes.head;
- initializerDo(parameterNode, (n) => n.accept(this));
- // Field parameters (this.x) are not visible inside the constructor. The
- // fields they reference are visible, but must be resolved independently.
- if (element.kind == ElementKind.FIELD_PARAMETER) {
- useElement(parameterNode, element);
- } else {
- defineElement(variableDefinitions.definitions.nodes.head, element);
- }
- parameterNodes = parameterNodes.tail;
- });
- }
-
- Element visitClassNode(ClassNode node) {
- cancel(node, "shouldn't be called");
- }
-
- visitIn(Node node, Scope scope) {
- context = scope;
- Element element = visit(node);
- context = context.parent;
- return element;
- }
-
- /**
- * Introduces new default targets for break and continue
- * before visiting the body of the loop
- */
- visitLoopBodyIn(Node loop, Node body, Scope scope) {
- TargetElement element = getOrCreateTargetElement(loop);
- statementScope.enterLoop(element);
- visitIn(body, scope);
- statementScope.exitLoop();
- if (!element.isTarget) {
- mapping.remove(loop);
- }
- }
-
- visitBlock(Block node) {
- visitIn(node.statements, new BlockScope(context));
- }
-
- visitDoWhile(DoWhile node) {
- visitLoopBodyIn(node, node.body, new BlockScope(context));
- visit(node.condition);
- }
-
- visitEmptyStatement(EmptyStatement node) { }
-
- visitExpressionStatement(ExpressionStatement node) {
- visit(node.expression);
- }
-
- visitFor(For node) {
- Scope scope = new BlockScope(context);
- visitIn(node.initializer, scope);
- visitIn(node.condition, scope);
- visitIn(node.update, scope);
- visitLoopBodyIn(node, node.body, scope);
- }
-
- visitFunctionDeclaration(FunctionDeclaration node) {
- assert(node.function.name !== null);
- visit(node.function);
- FunctionElement functionElement = mapping[node.function];
- // TODO(floitsch): this might lead to two errors complaining about
- // shadowing.
- defineElement(node, functionElement);
- }
-
- visitFunctionExpression(FunctionExpression node) {
- visit(node.returnType);
- SourceString name;
- if (node.name === null) {
- name = const SourceString("");
- } else {
- name = node.name.asIdentifier().source;
- }
- FunctionElement enclosing = new FunctionElement.node(
- name, node, ElementKind.FUNCTION, new Modifiers.empty(),
- context.element);
- setupFunction(node, enclosing);
- defineElement(node, enclosing, doAddToScope: node.name !== null);
-
- // Run the body in a fresh statement scope.
- StatementScope oldScope = statementScope;
- statementScope = new StatementScope();
- visit(node.body);
- statementScope = oldScope;
-
- context = context.parent;
- }
-
- visitIf(If node) {
- visit(node.condition);
- visit(node.thenPart);
- visit(node.elsePart);
- }
-
- static bool isLogicalOperator(Identifier op) {
- String str = op.source.stringValue;
- return (str === '&&' || str == '||' || str == '!');
- }
-
- Element resolveSend(Send node) {
- if (node.receiver === null) {
- return node.selector.accept(this);
- }
- var oldCategory = allowedCategory;
- allowedCategory |=
- ElementCategory.CLASS | ElementCategory.PREFIX | ElementCategory.SUPER;
- Element resolvedReceiver = visit(node.receiver);
- allowedCategory = oldCategory;
-
- Element target;
- SourceString name = node.selector.asIdentifier().source;
- if (name.stringValue === 'this') {
- error(node.selector, MessageKind.GENERIC, ["expected an identifier"]);
- } else if (node.isSuperCall) {
- if (node.isOperator) {
- if (isUserDefinableOperator(name.stringValue)) {
- name = Elements.constructOperatorName(const SourceString('operator'),
- name);
- } else {
- error(node.selector, MessageKind.ILLEGAL_SUPER_SEND, [name]);
- }
- }
- if (!inInstanceContext) {
- error(node.receiver, MessageKind.NO_INSTANCE_AVAILABLE, [name]);
- return null;
- }
- if (currentClass.supertype === null) {
- // This is just to guard against internal errors, so no need
- // for a real error message.
- error(node.receiver, MessageKind.GENERIC, ["Object has no superclass"]);
- }
- target = currentClass.lookupSuperMember(name);
- // [target] may be null which means invoking noSuchMethod on
- // super.
- } else if (resolvedReceiver === null) {
- return null;
- } else if (resolvedReceiver.kind === ElementKind.CLASS) {
- ClassElement receiverClass = resolvedReceiver;
- target = receiverClass.ensureResolved(compiler).lookupLocalMember(name);
- if (target === null) {
- error(node, MessageKind.METHOD_NOT_FOUND, [receiverClass.name, name]);
- } else if (target.isInstanceMember()) {
- error(node, MessageKind.MEMBER_NOT_STATIC, [receiverClass.name, name]);
- }
- } else if (resolvedReceiver.kind === ElementKind.PREFIX) {
- PrefixElement prefix = resolvedReceiver;
- target = prefix.lookupLocalMember(name);
- if (target == null) {
- error(node, MessageKind.NO_SUCH_LIBRARY_MEMBER, [prefix.name, name]);
- }
- }
- return target;
- }
-
- resolveTypeTest(Node argument) {
- TypeAnnotation node = argument.asTypeAnnotation();
- if (node == null) {
- node = argument.asSend().receiver;
- }
- resolveTypeRequired(node);
- }
-
- void handleArguments(Send node) {
- int count = 0;
- List<SourceString> namedArguments = <SourceString>[];
- bool seenNamedArgument = false;
- for (Link<Node> link = node.argumentsNode.nodes;
- !link.isEmpty();
- link = link.tail) {
- count++;
- Expression argument = link.head;
- visit(argument);
- if (argument.asNamedArgument() != null) {
- seenNamedArgument = true;
- NamedArgument named = argument;
- namedArguments.add(named.name.source);
- } else if (seenNamedArgument) {
- error(argument, MessageKind.INVALID_ARGUMENT_AFTER_NAMED);
- }
- }
- mapping.setSelector(node, new Invocation(count, namedArguments));
- }
-
- visitSend(Send node) {
- Element target = resolveSend(node);
- if (node.isOperator) {
- Operator op = node.selector.asOperator();
- if (op.source.stringValue === 'is') {
- resolveTypeTest(node.arguments.head);
- assert(node.arguments.tail.isEmpty());
- mapping.setSelector(node, Selector.BINARY_OPERATOR);
- } else if (node.arguments.isEmpty()) {
- assert(op.token.kind !== PLUS_TOKEN);
- mapping.setSelector(node, Selector.UNARY_OPERATOR);
- } else {
- visit(node.argumentsNode);
- mapping.setSelector(node, Selector.BINARY_OPERATOR);
- }
- } else if (node.isIndex) {
- visit(node.argumentsNode);
- assert(node.arguments.tail.isEmpty());
- mapping.setSelector(node, Selector.INDEX);
- } else if (node.isPropertyAccess) {
- mapping.setSelector(node, Selector.GETTER);
- } else {
- handleArguments(node);
- }
- if (target != null && target.kind == ElementKind.ABSTRACT_FIELD) {
- AbstractFieldElement field = target;
- target = field.getter;
- }
- // TODO(ngeoffray): Warn if target is null and the send is
- // unqualified.
- useElement(node, target);
- if (node.isPropertyAccess) return target;
- }
-
- visitSendSet(SendSet node) {
- Element target = resolveSend(node);
- Element setter = null;
- Element getter = null;
- if (target != null && target.kind == ElementKind.ABSTRACT_FIELD) {
- AbstractFieldElement field = target;
- setter = field.setter;
- getter = field.getter;
- } else {
- setter = target;
- getter = target;
- }
- // TODO(ngeoffray): Check if the target can be assigned.
- Identifier op = node.assignmentOperator;
- bool needsGetter = op.source.stringValue !== '=';
- Selector selector;
- if (needsGetter) {
- if (node.isIndex) {
- selector = Selector.INDEX_AND_INDEX_SET;
- } else {
- selector = Selector.GETTER_AND_SETTER;
- }
- useElement(node.selector, getter);
- } else if (node.isIndex) {
- selector = Selector.INDEX_SET;
- } else {
- selector = Selector.SETTER;
- }
- visit(node.argumentsNode);
- mapping.setSelector(node, selector);
- // TODO(ngeoffray): Warn if target is null and the send is
- // unqualified.
- return useElement(node, setter);
- }
-
- visitLiteralInt(LiteralInt node) {
- }
-
- visitLiteralDouble(LiteralDouble node) {
- }
-
- visitLiteralBool(LiteralBool node) {
- }
-
- visitLiteralString(LiteralString node) {
- }
-
- visitLiteralNull(LiteralNull node) {
- }
-
- visitStringJuxtaposition(StringJuxtaposition node) {
- node.visitChildren(this);
- }
-
- visitNodeList(NodeList node) {
- for (Link<Node> link = node.nodes; !link.isEmpty(); link = link.tail) {
- visit(link.head);
- }
- }
-
- visitOperator(Operator node) {
- unimplemented(node, 'operator');
- }
-
- visitReturn(Return node) {
- visit(node.expression);
- }
-
- visitThrow(Throw node) {
- visit(node.expression);
- }
-
- visitVariableDefinitions(VariableDefinitions node) {
- visit(node.type);
- VariableDefinitionsVisitor visitor =
- new VariableDefinitionsVisitor(compiler, node, this,
- ElementKind.VARIABLE);
- visitor.visit(node.definitions);
- }
-
- visitWhile(While node) {
- visit(node.condition);
- visitLoopBodyIn(node, node.body, new BlockScope(context));
- }
-
- visitParenthesizedExpression(ParenthesizedExpression node) {
- visit(node.expression);
- }
-
- visitNewExpression(NewExpression node) {
- Node selector = node.send.selector;
-
- FunctionElement constructor = resolveConstructor(node);
- handleArguments(node.send);
- if (constructor === null) return null;
- // TODO(karlklose): handle optional arguments.
- if (node.send.argumentCount() != constructor.parameterCount(compiler)) {
- // TODO(ngeoffray): resolution error with wrong number of
- // parameters. We cannot do this rigth now because of the
- // List constructor.
- }
- useElement(node.send, constructor);
- return null;
- }
-
- FunctionElement resolveConstructor(NewExpression node) {
- FunctionElement constructor =
- node.accept(new ConstructorResolver(compiler, this));
- if (constructor === null) {
- Element resolved = resolveTypeRequired(node.send.selector);
- if (resolved !== null && resolved.kind === ElementKind.TYPE_VARIABLE) {
- error(node, WarningKind.TYPE_VARIABLE_AS_CONSTRUCTOR);
- return null;
- } else {
- error(node.send, MessageKind.CANNOT_FIND_CONSTRUCTOR, [node.send]);
- }
- }
- return constructor;
- }
-
- Element resolveTypeRequired(Node node) {
- bool old = typeRequired;
- typeRequired = true;
- Element element = visit(node);
- typeRequired = old;
- return element;
- }
-
- visitModifiers(Modifiers node) {
- // TODO(ngeoffray): Implement this.
- unimplemented(node, 'modifiers');
- }
-
- visitLiteralList(LiteralList node) {
- visit(node.elements);
- }
-
- visitConditional(Conditional node) {
- node.visitChildren(this);
- }
-
- visitStringInterpolation(StringInterpolation node) {
- node.visitChildren(this);
- }
-
- visitStringInterpolationPart(StringInterpolationPart node) {
- node.visitChildren(this);
- }
-
- visitBreakStatement(BreakStatement node) {
- TargetElement target;
- if (node.target === null) {
- target = statementScope.currentBreakTarget();
- if (target === null) {
- error(node, MessageKind.NO_BREAK_TARGET);
- return;
- }
- target.isBreakTarget = true;
- } else {
- String labelName = node.target.source.slowToString();
- LabelElement label = statementScope.lookupLabel(labelName);
- if (label === null) {
- error(node.target, MessageKind.UNBOUND_LABEL, [labelName]);
- return;
- }
- target = label.target;
- if (!target.statement.isValidBreakTarget()) {
- error(node.target, MessageKind.INVALID_BREAK, [labelName]);
- return;
- }
- label.setBreakTarget();
- mapping[node.target] = label;
- }
- mapping[node] = target;
- }
-
- visitContinueStatement(ContinueStatement node) {
- TargetElement target;
- if (node.target === null) {
- target = statementScope.currentContinueTarget();
- if (target === null) {
- error(node, MessageKind.NO_CONTINUE_TARGET);
- return;
- }
- target.isContinueTarget = true;
- } else {
- String labelName = node.target.source.slowToString();
- LabelElement label = statementScope.lookupLabel(labelName);
- if (label === null) {
- error(node.target, MessageKind.UNBOUND_LABEL, [labelName]);
- return;
- }
- target = label.target;
- if (!target.statement.isValidContinueTarget()) {
- error(node.target, MessageKind.INVALID_CONTINUE, [labelName]);
- }
- label.setContinueTarget();
- }
- mapping[node] = target;
- }
-
- visitForInStatement(ForInStatement node) {
- visit(node.expression);
- Scope scope = new BlockScope(context);
- Node declaration = node.declaredIdentifier;
- visitIn(declaration, scope);
- visitLoopBodyIn(node, node.body, scope);
-
- // TODO(lrn): Also allow a single identifier.
- if ((declaration is !Send || declaration.asSend().selector is !Identifier)
- && (declaration is !VariableDefinitions ||
- !declaration.asVariableDefinitions().definitions.nodes.tail.isEmpty()))
- {
- // The variable declaration is either not an identifier, not a
- // declaration, or it's declaring more than one variable.
- error(node.declaredIdentifier, MessageKind.INVALID_FOR_IN, []);
- }
- }
-
- visitLabeledStatement(LabeledStatement node) {
- String labelName = node.label.source.slowToString();
- LabelElement existingElement = statementScope.lookupLabel(labelName);
- if (existingElement !== null) {
- warning(node.label, MessageKind.DUPLICATE_LABEL, [labelName]);
- warning(existingElement.label, MessageKind.EXISTING_LABEL, [labelName]);
- }
- Node body = node.getBody();
- TargetElement targetElement = getOrCreateTargetElement(body);
-
- LabelElement element = targetElement.addLabel(node.label, labelName);
- statementScope.enterLabelScope(element);
- visit(node.statement);
- statementScope.exitLabelScope();
- if (element.isTarget) {
- mapping[node.label] = element;
- } else {
- warning(node.label, MessageKind.UNUSED_LABEL, [labelName]);
- }
- if (!targetElement.isTarget && mapping[body] === targetElement) {
- // If the body is itself a break or continue for another target, it
- // might have updated its mapping to the target it actually does target.
- mapping.remove(body);
- }
- }
-
- visitLiteralMap(LiteralMap node) {
- node.visitChildren(this);
- }
-
- visitLiteralMapEntry(LiteralMapEntry node) {
- node.visitChildren(this);
- }
-
- visitNamedArgument(NamedArgument node) {
- visit(node.expression);
- }
-
- visitSwitchStatement(SwitchStatement node) {
- node.expression.accept(this);
-
- TargetElement breakElement = getOrCreateTargetElement(node);
- Map<String, LabelElement> continueLabels = <LabelElement>{};
- Link<Node> cases = node.cases.nodes;
- while (!cases.isEmpty()) {
- SwitchCase switchCase = cases.head;
- if (switchCase.label !== null) {
- Identifier labelIdentifier = switchCase.label;
- String labelName = labelIdentifier.source.slowToString();
-
- LabelElement existingElement = continueLabels[labelName];
- if (existingElement !== null) {
- // It's an error if the same label occurs twice in the same switch.
- warning(labelIdentifier, MessageKind.DUPLICATE_LABEL, [labelName]);
- error(existingElement.label, MessageKind.EXISTING_LABEL, [labelName]);
- } else {
- // It's only a warning if it shadows another label.
- existingElement = statementScope.lookupLabel(labelName);
- if (existingElement !== null) {
- warning(labelIdentifier, MessageKind.DUPLICATE_LABEL, [labelName]);
- warning(existingElement.label,
- MessageKind.EXISTING_LABEL, [labelName]);
- }
- }
-
- TargetElement TargetElement =
- new TargetElement(switchCase,
- statementScope.nestingLevel,
- enclosingElement);
- mapping[switchCase] = TargetElement;
-
- LabelElement label =
- new LabelElement(labelIdentifier, labelName,
- TargetElement, enclosingElement);
- mapping[labelIdentifier] = label;
- continueLabels[labelName] = label;
- }
- cases = cases.tail;
- if (switchCase.defaultKeyword !== null && !cases.isEmpty()) {
- error(switchCase, MessageKind.INVALID_CASE_DEFAULT);
- }
- }
- statementScope.enterSwitch(breakElement, continueLabels);
- node.cases.accept(this);
- statementScope.exitSwitch();
-
- // Clean-up unused labels
- continueLabels.forEach((String key, LabelElement label) {
- TargetElement TargetElement = label.target;
- SwitchCase switchCase = TargetElement.statement;
- if (!label.isContinueTarget) {
- mapping.remove(switchCase);
- mapping.remove(label.label);
- }
- });
- }
-
- visitSwitchCase(SwitchCase node) {
- // The label was handled in [visitSwitchStatement(SwitchStatement)].
- node.expressions.accept(this);
- visitIn(node.statements, new BlockScope(context));
- }
-
- visitTryStatement(TryStatement node) {
- visit(node.tryBlock);
- if (node.catchBlocks.isEmpty() && node.finallyBlock == null) {
- // TODO(ngeoffray): The precise location is
- // node.getEndtoken.next. Adjust when issue #1581 is fixed.
- error(node, MessageKind.NO_CATCH_NOR_FINALLY);
- }
- visit(node.catchBlocks);
- visit(node.finallyBlock);
- }
-
- visitCatchBlock(CatchBlock node) {
- Scope scope = new BlockScope(context);
- if (node.formals.isEmpty()) {
- error(node, MessageKind.EMPTY_CATCH_DECLARATION);
- } else if (!node.formals.nodes.tail.isEmpty()
- && !node.formals.nodes.tail.tail.isEmpty()) {
- for (Node extra in node.formals.nodes.tail.tail) {
- error(extra, MessageKind.EXTRA_CATCH_DECLARATION);
- }
- }
- visitIn(node.formals, scope);
- visitIn(node.block, scope);
- }
-
- visitTypedef(Typedef node) {
- unimplemented(node, 'typedef');
- }
-}
-
-class ClassResolverVisitor extends CommonResolverVisitor<Type> {
- Scope context;
- ClassElement classElement;
-
- ClassResolverVisitor(Compiler compiler, LibraryElement library,
- ClassElement this.classElement)
- : context = new TopScope(library),
- super(compiler);
-
- Type visitClassNode(ClassNode node) {
- compiler.ensure(classElement !== null);
- compiler.ensure(!classElement.isResolved);
- final Link<Node> parameters =
- node.typeParameters !== null ? node.typeParameters.nodes
- : const EmptyLink<TypeVariable>();
- // Create types and elements for type variable.
- for (Link<Node> link = parameters; !link.isEmpty(); link = link.tail) {
- TypeVariable typeNode = link.head;
- SourceString variableName = typeNode.name.source;
- TypeVariableType variableType = new TypeVariableType(variableName);
- TypeVariableElement variableElement =
- new TypeVariableElement(variableName, classElement, node,
- variableType);
- variableType.element = variableElement;
- classElement.typeParameters[variableName] = variableElement;
- context = new TypeVariablesScope(context, classElement);
- }
- // Resolve the bounds of type variables.
- for (Link<Node> link = parameters; !link.isEmpty(); link = link.tail) {
- TypeVariable typeNode = link.head;
- SourceString variableName = typeNode.name.source;
- TypeVariableElement variableElement =
- classElement.typeParameters[variableName];
- if (typeNode.bound !== null) {
- Type boundType = visit(typeNode.bound);
- if (boundType !== null && boundType.element == variableElement) {
- warning(node, MessageKind.CYCLIC_TYPE_VARIABLE,
- [variableElement.name]);
- } else if (boundType !== null) {
- variableElement.bound = boundType;
- } else {
- variableElement.bound = compiler.objectClass.computeType(compiler);
- }
- }
- }
- // Find super type.
- Type supertype = visit(node.superclass);
- if (supertype !== null && supertype.element.isExtendable()) {
- classElement.supertype = supertype;
- if (isBlackListed(supertype)) {
- error(node.superclass, MessageKind.CANNOT_EXTEND, [supertype]);
- }
- } else if (supertype !== null) {
- error(node.superclass, MessageKind.TYPE_NAME_EXPECTED);
- }
- if (classElement.name != Types.OBJECT && classElement.supertype === null) {
- ClassElement objectElement = context.lookup(Types.OBJECT);
- if (objectElement !== null && !objectElement.isResolved) {
- compiler.resolver.toResolve.add(objectElement);
- } else if (objectElement === null){
- error(node, MessageKind.CANNOT_RESOLVE_TYPE, [Types.OBJECT]);
- }
- classElement.supertype = new SimpleType(Types.OBJECT, objectElement);
- }
- if (node.defaultClause !== null) {
- classElement.defaultClass = visit(node.defaultClause);
- }
- for (Link<Node> link = node.interfaces.nodes;
- !link.isEmpty();
- link = link.tail) {
- Type interfaceType = visit(link.head);
- if (interfaceType !== null && interfaceType.element.isExtendable()) {
- classElement.interfaces =
- classElement.interfaces.prepend(interfaceType);
- if (isBlackListed(interfaceType)) {
- error(link.head, MessageKind.CANNOT_IMPLEMENT, [interfaceType]);
- }
- } else {
- error(link.head, MessageKind.TYPE_NAME_EXPECTED);
- }
- }
- calculateAllSupertypes(classElement, new Set<ClassElement>());
- addDefaultConstructorIfNeeded(classElement);
- return classElement.computeType(compiler);
- }
-
- Type visitTypeAnnotation(TypeAnnotation node) {
- return visit(node.typeName);
- }
-
- Type visitIdentifier(Identifier node) {
- Element element = context.lookup(node.source);
- if (element === null) {
- error(node, MessageKind.CANNOT_RESOLVE_TYPE, [node]);
- return null;
- } else if (!element.impliesType() && !element.isTypeVariable()) {
- error(node, MessageKind.NOT_A_TYPE, [node]);
- return null;
- } else {
- if (element.isClass()) {
- compiler.resolver.toResolve.add(element);
- }
- if (element.isTypeVariable()) {
- TypeVariableElement variableElement = element;
- return variableElement.type;
- } else if (element.isTypedef()) {
- compiler.unimplemented('visitIdentifier for typedefs');
- } else {
- // TODO(ngeoffray): Use type variables.
- return element.computeType(compiler);
- }
- }
- return null;
- }
-
- Type visitSend(Send node) {
- Identifier prefix = node.receiver.asIdentifier();
- if (prefix === null) {
- error(node.receiver, MessageKind.NOT_A_PREFIX, [node.receiver]);
- return null;
- }
- Element element = context.lookup(prefix.source);
- if (element === null || element.kind !== ElementKind.PREFIX) {
- error(node.receiver, MessageKind.NOT_A_PREFIX, [node.receiver]);
- return null;
- }
- PrefixElement prefixElement = element;
- Identifier selector = node.selector.asIdentifier();
- var e = prefixElement.lookupLocalMember(selector.source);
- if (e === null || !e.impliesType()) {
- error(node.selector, MessageKind.CANNOT_RESOLVE_TYPE, [node.selector]);
- return null;
- }
- return e.computeType(compiler);
- }
-
- Link<Type> getOrCalculateAllSupertypes(ClassElement classElement,
- [Set<ClassElement> seen]) {
- Link<Type> allSupertypes = classElement.allSupertypes;
- if (allSupertypes !== null) return allSupertypes;
- if (seen === null) {
- seen = new Set<ClassElement>();
- }
- if (seen.contains(classElement)) {
- error(classElement.parseNode(compiler),
- MessageKind.CYCLIC_CLASS_HIERARCHY,
- [classElement.name]);
- classElement.allSupertypes = const EmptyLink<Type>();
- } else {
- classElement.ensureResolved(compiler);
- calculateAllSupertypes(classElement, seen);
- }
- return classElement.allSupertypes;
- }
-
- void calculateAllSupertypes(ClassElement classElement,
- Set<ClassElement> seen) {
- // TODO(karlklose): substitute type variables.
- // TODO(karlklose): check if type arguments match, if a classelement occurs
- // more than once in the supertypes.
- if (classElement.allSupertypes !== null) return;
- final Type supertype = classElement.supertype;
- if (seen.contains(classElement)) {
- error(classElement.parseNode(compiler),
- MessageKind.CYCLIC_CLASS_HIERARCHY,
- [classElement.name]);
- classElement.allSupertypes = const EmptyLink<Type>();
- } else if (supertype != null) {
- seen.add(classElement);
- Link<Type> superSupertypes =
- getOrCalculateAllSupertypes(supertype.element, seen);
- Link<Type> supertypes = new Link<Type>(supertype, superSupertypes);
- for (Link<Type> interfaces = classElement.interfaces;
- !interfaces.isEmpty();
- interfaces = interfaces.tail) {
- Element element = interfaces.head.element;
- Link<Type> interfaceSupertypes =
- getOrCalculateAllSupertypes(element, seen);
- supertypes = supertypes.reversePrependAll(interfaceSupertypes);
- supertypes = supertypes.prepend(interfaces.head);
- }
- seen.remove(classElement);
- classElement.allSupertypes = supertypes;
- } else {
- classElement.allSupertypes = const EmptyLink<Type>();
- }
- }
-
- /**
- * Add a synthetic nullary constructor if there are no other
- * constructors.
- */
- void addDefaultConstructorIfNeeded(ClassElement element) {
- if (element.constructors.length != 0) return;
- SynthesizedConstructorElement constructor =
- new SynthesizedConstructorElement(element);
- element.constructors[element.name] = constructor;
- Type returnType = compiler.types.voidType;
- constructor.type = new FunctionType(returnType, const EmptyLink<Type>(),
- constructor);
- constructor.cachedNode =
- new FunctionExpression(new Identifier(element.position()),
- new NodeList.empty(),
- new Block(new NodeList.empty()),
- null, null, null, null);
- }
-
- isBlackListed(Type type) {
- LibraryElement lib = classElement.getLibrary();
- return
- lib !== compiler.coreLibrary &&
- lib !== compiler.coreImplLibrary &&
- lib !== compiler.jsHelperLibrary &&
- (type.element === compiler.dynamicClass ||
- type.element === compiler.boolClass ||
- type.element === compiler.numClass ||
- type.element === compiler.intClass ||
- type.element === compiler.doubleClass ||
- type.element === compiler.stringClass ||
- type.element === compiler.nullClass ||
- type.element === compiler.functionClass);
- }
-}
-
-class VariableDefinitionsVisitor extends CommonResolverVisitor<SourceString> {
- VariableDefinitions definitions;
- ResolverVisitor resolver;
- ElementKind kind;
- VariableListElement variables;
-
- VariableDefinitionsVisitor(Compiler compiler,
- this.definitions, this.resolver, this.kind)
- : super(compiler)
- {
- variables = new VariableListElement.node(
- definitions, ElementKind.VARIABLE_LIST, resolver.context.element);
- }
-
- SourceString visitSendSet(SendSet node) {
- assert(node.arguments.tail.isEmpty()); // Sanity check
- resolver.visit(node.arguments.head);
- return visit(node.selector);
- }
-
- SourceString visitIdentifier(Identifier node) => node.source;
-
- visitNodeList(NodeList node) {
- for (Link<Node> link = node.nodes; !link.isEmpty(); link = link.tail) {
- SourceString name = visit(link.head);
- VariableElement element = new VariableElement(
- name, variables, kind, resolver.context.element, node: link.head);
- resolver.defineElement(link.head, element);
- }
- }
-}
-
-class SignatureResolver extends CommonResolverVisitor<Element> {
- final Element enclosingElement;
- Link<Element> optionalParameters = const EmptyLink<Element>();
- int optionalParameterCount = 0;
- Node currentDefinitions;
-
- SignatureResolver(Compiler compiler, this.enclosingElement) : super(compiler);
-
- Element visitNodeList(NodeList node) {
- // This must be a list of optional arguments.
- if (node.beginToken.stringValue !== '[') {
- internalError(node, "expected optional parameters");
- }
- LinkBuilder<Element> elements = analyzeNodes(node.nodes);
- optionalParameterCount = elements.length;
- optionalParameters = elements.toLink();
- return null;
- }
-
- Element visitVariableDefinitions(VariableDefinitions node) {
- resolveType(node.type);
-
- Link<Node> definitions = node.definitions.nodes;
- if (definitions.isEmpty()) {
- cancel(node, 'internal error: no parameter definition');
- return null;
- }
- if (!definitions.tail.isEmpty()) {
- cancel(definitions.tail.head, 'internal error: extra definition');
- return null;
- }
- Node definition = definitions.head;
- if (definition is NodeList) {
- cancel(node, 'optional parameters are not implemented');
- }
-
- if (currentDefinitions != null) {
- cancel(node, 'function type parameters not supported');
- }
- currentDefinitions = node;
- Element element = definition.accept(this);
- currentDefinitions = null;
- return element;
- }
-
- Element visitIdentifier(Identifier node) {
- Element variables = new VariableListElement.node(currentDefinitions,
- ElementKind.VARIABLE_LIST, enclosingElement);
- return new VariableElement(node.source, variables,
- ElementKind.PARAMETER, enclosingElement, node: node);
- }
-
- // The only valid [Send] can be in constructors and must be of the form
- // [:this.x:] (where [:x:] represents an instance field).
- FieldParameterElement visitSend(Send node) {
- FieldParameterElement element;
- if (node.receiver.asIdentifier() === null ||
- !node.receiver.asIdentifier().isThis()) {
- error(node, MessageKind.INVALID_PARAMETER, []);
- } else if (enclosingElement.kind !== ElementKind.GENERATIVE_CONSTRUCTOR) {
- error(node, MessageKind.FIELD_PARAMETER_NOT_ALLOWED, []);
- } else {
- if (node.selector.asIdentifier() == null) {
- cancel(node,
- 'internal error: unimplemented receiver on parameter send');
- }
- SourceString name = node.selector.asIdentifier().source;
- Element fieldElement = currentClass.lookupLocalMember(name);
- if (fieldElement === null || fieldElement.kind !== ElementKind.FIELD) {
- error(node, MessageKind.NOT_A_FIELD, [name]);
- } else if (!fieldElement.isInstanceMember()) {
- error(node, MessageKind.NOT_INSTANCE_FIELD, [name]);
- }
- Element variables = new VariableListElement.node(currentDefinitions,
- ElementKind.VARIABLE_LIST, enclosingElement);
- element = new FieldParameterElement(node.selector.asIdentifier().source,
- fieldElement, variables, enclosingElement, node);
- }
- return element;
- }
-
- Element visitSendSet(SendSet node) {
- Element element;
- if (node.receiver != null) {
- element = visitSend(node);
- } else if (node.selector.asIdentifier() != null) {
- Element variables = new VariableListElement.node(currentDefinitions,
- ElementKind.VARIABLE_LIST, enclosingElement);
- element = new VariableElement(node.selector.asIdentifier().source,
- variables, ElementKind.PARAMETER, enclosingElement, node: node);
- }
- // Visit the value. The compile time constant handler will
- // make sure it's a compile time constant.
- resolveExpression(node.arguments.head);
- compiler.enqueue(new WorkItem.toCompile(element));
- return element;
- }
-
- Element visitFunctionExpression(FunctionExpression node) {
- // This is a function typed parameter.
- // TODO(ahe): Resolve the function type.
- return visit(node.name);
- }
-
- LinkBuilder<Element> analyzeNodes(Link<Node> link) {
- LinkBuilder<Element> elements = new LinkBuilder<Element>();
- for (; !link.isEmpty(); link = link.tail) {
- Element element = link.head.accept(this);
- if (element != null) {
- elements.addLast(element);
- } else {
- // If parameter is null, the current node should be the last,
- // and a list of optional named parameters.
- if (!link.tail.isEmpty() || (link.head is !NodeList)) {
- internalError(link.head, "expected optional parameters");
- }
- }
- }
- return elements;
- }
-
- static FunctionParameters analyze(Compiler compiler,
- FunctionElement element) {
- FunctionExpression node = element.parseNode(compiler);
- SignatureResolver visitor = new SignatureResolver(compiler, element);
- Link<Node> nodes = node.parameters.nodes;
- LinkBuilder<Element> parameters = visitor.analyzeNodes(nodes);
- return new FunctionParameters(parameters.toLink(),
- visitor.optionalParameters,
- parameters.length,
- visitor.optionalParameterCount);
- }
-
- // TODO(ahe): This is temporary.
- void resolveExpression(Node node) {
- if (node == null) return;
- node.accept(new ResolverVisitor(compiler, enclosingElement));
- }
-
- // TODO(ahe): This is temporary.
- void resolveType(Node node) {
- if (node == null) return;
- node.accept(new ResolverVisitor(compiler, enclosingElement));
- }
-
- // TODO(ahe): This is temporary.
- ClassElement get currentClass() {
- return enclosingElement.isMember()
- ? enclosingElement.enclosingElement : null;
- }
-}
-
-class ConstructorResolver extends CommonResolverVisitor<Element> {
- final ResolverVisitor resolver;
- ConstructorResolver(Compiler compiler, this.resolver) : super(compiler);
-
- visitNode(Node node) {
- throw 'not supported';
- }
-
- visitNewExpression(NewExpression node) {
- Node selector = node.send.selector;
- Element e = visit(selector);
- if (e !== null && e.kind === ElementKind.CLASS) {
- ClassElement cls = e;
- cls.ensureResolved(compiler);
- compiler.resolver.toResolve.add(cls);
- if (cls.isInterface() && (cls.defaultClass === null)) {
- error(selector, MessageKind.CANNOT_INSTANTIATE_INTERFACE, [cls.name]);
- }
- e = cls.lookupConstructor(cls.name);
- }
- return e;
- }
-
- visitTypeAnnotation(TypeAnnotation node) {
- // TODO(ahe): Do not ignore type arguments.
- return visit(node.typeName);
- }
-
- visitSend(Send node) {
- Element e = visit(node.receiver);
- if (e === null) return null; // TODO(ahe): Return erroneous element.
-
- Identifier name = node.selector.asIdentifier();
- if (name === null) internalError(node.selector, 'unexpected node');
-
- if (e.kind === ElementKind.CLASS) {
- ClassElement cls = e;
- cls.ensureResolved(compiler);
- compiler.resolver.toResolve.add(cls);
- if (cls.isInterface() && (cls.defaultClass === null)) {
- error(node.receiver, MessageKind.CANNOT_INSTANTIATE_INTERFACE,
- [cls.name]);
- }
- SourceString constructorName =
- Elements.constructConstructorName(cls.name, name.source);
- FunctionElement constructor = cls.lookupConstructor(constructorName);
- if (constructor === null) {
- error(name, MessageKind.CANNOT_FIND_CONSTRUCTOR, [name]);
- }
- e = constructor;
- } else if (e.kind === ElementKind.PREFIX) {
- PrefixElement prefix = e;
- e = prefix.lookupLocalMember(name.source);
- if (e === null) {
- error(name, MessageKind.CANNOT_RESOLVE, [name]);
- // TODO(ahe): Return erroneous element.
- } else if (e.kind !== ElementKind.CLASS) {
- error(node, MessageKind.NOT_A_TYPE, [name]);
- }
- } else {
- internalError(node.receiver, 'unexpected element $e');
- }
- return e;
- }
-
- Element visitIdentifier(Identifier node) {
- SourceString name = node.source;
- Element e = resolver.lookup(node, name);
- if (e === null) {
- error(node, MessageKind.CANNOT_RESOLVE, [name]);
- // TODO(ahe): Return erroneous element.
- } else if (e.kind === ElementKind.TYPEDEF) {
- error(node, MessageKind.CANNOT_INSTANTIATE_TYPEDEF, [name]);
- } else if (e.kind !== ElementKind.CLASS && e.kind !== ElementKind.PREFIX) {
- error(node, MessageKind.NOT_A_TYPE, [name]);
- }
- return e;
- }
-}
-
-class Scope {
- final Element element;
- final Scope parent;
-
- Scope(this.parent, this.element);
- abstract Element add(Element element);
- abstract Element lookup(SourceString name);
-}
-
-class TypeVariablesScope extends Scope {
- TypeVariablesScope(parent, ClassElement element) : super(parent, element);
- Element add(Element element) {
- throw "Cannot add element to TypeVariableScope";
- }
- Element lookup(SourceString name) {
- ClassElement cls = element;
- Element result = cls.lookupTypeParameter(name);
- if (result !== null) return result;
- if (parent !== null) return parent.lookup(name);
- }
-}
-
-class MethodScope extends Scope {
- final Map<SourceString, Element> elements;
-
- MethodScope(Scope parent, Element element)
- : super(parent, element), this.elements = new Map<SourceString, Element>();
-
- Element lookup(SourceString name) {
- Element element = elements[name];
- if (element !== null) return element;
- return parent.lookup(name);
- }
-
- Element add(Element element) {
- if (elements.containsKey(element.name)) return elements[element.name];
- elements[element.name] = element;
- return element;
- }
-}
-
-class BlockScope extends MethodScope {
- BlockScope(Scope parent) : super(parent, parent.element);
-}
-
-class ClassScope extends Scope {
- ClassScope(ClassElement element, LibraryElement library)
- : super(new TopScope(library), element);
-
- Element lookup(SourceString name) {
- ClassElement cls = element;
- Element result = cls.lookupLocalMember(name);
- if (result !== null) return result;
- result = cls.lookupTypeParameter(name);
- if (result !== null) return result;
- result = parent.lookup(name);
- if (result != null) return result;
- return cls.lookupSuperMember(name);
- }
-
- Element add(Element element) {
- throw "Cannot add an element in a class scope";
- }
-}
-
-class TopScope extends Scope {
- LibraryElement get library() => element;
-
- TopScope(LibraryElement library) : super(null, library);
- Element lookup(SourceString name) {
- return library.find(name);
- }
-
- Element add(Element element) {
- throw "Cannot add an element in the top scope";
- }
-}
« no previous file with comments | « frog/leg/operations.dart ('k') | frog/leg/scanner/array_based_scanner.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698