blob: cd6de0e86e26717078103c77e42c6d272c6e9d38 [file] [log] [blame]
// 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));
}
}