blob: 2346ebff1b1a389cfe186f075d0ead25dd8cf511 [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 '../common.dart';
import '../elements/elements.dart' show Element, ElementKind, Elements;
import '../elements/modelx.dart'
show ClassElementX, ElementX, FieldElementX, VariableList;
import 'package:front_end/src/fasta/scanner.dart' show Token;
import '../tree/tree.dart';
import 'element_listener.dart' show ScannerOptions;
import 'node_listener.dart' show NodeListener;
import 'partial_elements.dart'
show
PartialConstructorElement,
PartialFunctionElement,
PartialMetadataAnnotation;
class MemberListener extends NodeListener {
final ClassElementX enclosingClass;
MemberListener(ScannerOptions scannerOptions, DiagnosticReporter listener,
ClassElementX enclosingElement)
: this.enclosingClass = enclosingElement,
super(scannerOptions, 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) {
reporter.reportErrorMessage(
send.receiver,
MessageKind.INVALID_CONSTRUCTOR_NAME,
{'name': enclosingClass.name});
}
return selector.source;
}
}
@override
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(reporter.spanFromToken(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);
}
@override
void endFactoryMethod(
Token beginToken, Token factoryKeyword, Token endToken) {
super.endFactoryMethod(beginToken, factoryKeyword, 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) {
reporter.reportErrorMessage(
singleIdentifierName,
MessageKind.INVALID_UNNAMED_CONSTRUCTOR_NAME,
{'name': enclosingClass.name});
}
}
Element memberElement = new PartialConstructorElement(
name,
beginToken,
endToken,
ElementKind.FACTORY_CONSTRUCTOR,
method.modifiers,
enclosingClass);
addMember(memberElement);
}
@override
void endFields(
int count, Token covariantKeyword, Token beginToken, Token endToken) {
bool hasParseError = memberErrors.head;
super.endFields(count, covariantKeyword, 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);
}
@override
void endFieldInitializer(Token assignmentOperator) {
pushNode(null); // Super expects an expression, but
// ClassElementParser just skips expressions.
super.endFieldInitializer(assignmentOperator);
}
@override
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, reporter);
}
@override
void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
super.endMetadata(beginToken, periodBeforeName, endToken);
// TODO(paulberry,ahe): type variable metadata should not be ignored. See
// dartbug.com/5841.
if (!inTypeVariable) {
pushMetadata(new PartialMetadataAnnotation(beginToken, endToken));
}
}
}