| // Copyright (c) 2015, 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. |
| |
| library dart2js.parser.member_listener; |
| |
| import '../diagnostics/diagnostic_listener.dart' show |
| DiagnosticListener; |
| import '../diagnostics/messages.dart' show |
| MessageKind; |
| import '../elements/elements.dart' show |
| Element, |
| ElementKind, |
| Elements, |
| MetadataAnnotation; |
| import '../elements/modelx.dart' show |
| ClassElementX, |
| ElementX, |
| FieldElementX, |
| VariableList; |
| import '../tokens/token.dart' show |
| Token; |
| import '../tree/tree.dart'; |
| import '../util/util.dart' show |
| Link; |
| |
| import 'partial_elements.dart' show |
| PartialConstructorElement, |
| PartialFunctionElement, |
| PartialMetadataAnnotation; |
| import 'node_listener.dart' show |
| NodeListener; |
| |
| class MemberListener extends NodeListener { |
| final ClassElementX enclosingClass; |
| |
| MemberListener(DiagnosticListener listener, |
| ClassElementX enclosingElement) |
| : this.enclosingClass = enclosingElement, |
| super(listener, enclosingElement.compilationUnit); |
| |
| bool isConstructorName(Node nameNode) { |
| if (enclosingClass == null || |
| enclosingClass.kind != ElementKind.CLASS) { |
| return false; |
| } |
| String name; |
| if (nameNode.asIdentifier() != null) { |
| name = nameNode.asIdentifier().source; |
| } else { |
| Send send = nameNode.asSend(); |
| name = send.receiver.asIdentifier().source; |
| } |
| return enclosingClass.name == name; |
| } |
| |
| // TODO(johnniwinther): Remove this method. |
| String getMethodNameHack(Node methodName) { |
| Send send = methodName.asSend(); |
| if (send == null) { |
| if (isConstructorName(methodName)) return ''; |
| return methodName.asIdentifier().source; |
| } |
| Identifier receiver = send.receiver.asIdentifier(); |
| Identifier selector = send.selector.asIdentifier(); |
| Operator operator = selector.asOperator(); |
| if (operator != null) { |
| assert(identical(receiver.source, 'operator')); |
| // TODO(ahe): It is a hack to compare to ')', but it beats |
| // parsing the node. |
| bool isUnary = identical(operator.token.next.next.stringValue, ')'); |
| return Elements.constructOperatorName(operator.source, isUnary); |
| } else { |
| if (receiver == null || receiver.source != enclosingClass.name) { |
| listener.reportErrorMessage( |
| send.receiver, |
| MessageKind.INVALID_CONSTRUCTOR_NAME, |
| {'name': enclosingClass.name}); |
| } |
| return selector.source; |
| } |
| } |
| |
| void endMethod(Token getOrSet, Token beginToken, Token endToken) { |
| super.endMethod(getOrSet, beginToken, endToken); |
| FunctionExpression method = popNode(); |
| pushNode(null); |
| bool isConstructor = isConstructorName(method.name); |
| String name = getMethodNameHack(method.name); |
| Element memberElement; |
| if (isConstructor) { |
| if (getOrSet != null) { |
| recoverableError(getOrSet, 'illegal modifier'); |
| } |
| memberElement = new PartialConstructorElement( |
| name, beginToken, endToken, |
| ElementKind.GENERATIVE_CONSTRUCTOR, |
| method.modifiers, |
| enclosingClass); |
| } else { |
| memberElement = new PartialFunctionElement( |
| name, beginToken, getOrSet, endToken, |
| method.modifiers, enclosingClass, hasBody: method.hasBody()); |
| } |
| addMember(memberElement); |
| } |
| |
| void endFactoryMethod(Token beginToken, Token endToken) { |
| super.endFactoryMethod(beginToken, endToken); |
| FunctionExpression method = popNode(); |
| pushNode(null); |
| String name = getMethodNameHack(method.name); |
| Identifier singleIdentifierName = method.name.asIdentifier(); |
| if (singleIdentifierName != null && singleIdentifierName.source == name) { |
| if (name != enclosingClass.name) { |
| listener.reportErrorMessage( |
| singleIdentifierName, |
| MessageKind.INVALID_UNNAMED_CONSTRUCTOR_NAME, |
| {'name': enclosingClass.name}); |
| } |
| } |
| Element memberElement = new PartialConstructorElement( |
| name, beginToken, endToken, |
| ElementKind.FUNCTION, |
| method.modifiers, |
| enclosingClass); |
| addMember(memberElement); |
| } |
| |
| void endFields(int count, Token beginToken, Token endToken) { |
| bool hasParseError = memberErrors.head; |
| super.endFields(count, beginToken, endToken); |
| VariableDefinitions variableDefinitions = popNode(); |
| Modifiers modifiers = variableDefinitions.modifiers; |
| pushNode(null); |
| void buildFieldElement(Identifier name, VariableList fields) { |
| Element element = |
| new FieldElementX(name, enclosingClass, fields); |
| addMember(element); |
| } |
| buildFieldElements(modifiers, variableDefinitions.definitions, |
| enclosingClass, |
| buildFieldElement, beginToken, endToken, |
| hasParseError); |
| } |
| |
| void endInitializer(Token assignmentOperator) { |
| pushNode(null); // Super expects an expression, but |
| // ClassElementParser just skips expressions. |
| super.endInitializer(assignmentOperator); |
| } |
| |
| void endInitializers(int count, Token beginToken, Token endToken) { |
| pushNode(null); |
| } |
| |
| void addMetadata(ElementX memberElement) { |
| memberElement.metadata = metadata.toList(); |
| } |
| |
| void addMember(ElementX memberElement) { |
| addMetadata(memberElement); |
| enclosingClass.addMember(memberElement, listener); |
| } |
| |
| void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) { |
| popNode(); // Discard arguments. |
| if (periodBeforeName != null) { |
| popNode(); // Discard name. |
| } |
| popNode(); // Discard node (Send or Identifier). |
| pushMetadata(new PartialMetadataAnnotation(beginToken, endToken)); |
| } |
| } |