blob: d68e961d7c0df52b267dda01e4b0440fc5a6ab41 [file] [log] [blame]
// Copyright (c) 2014, 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.resolution.enum_creator;
import '../dart_types.dart';
import '../dart2jslib.dart';
import '../elements/elements.dart';
import '../elements/modelx.dart';
import '../scanner/scannerlib.dart';
import '../tree/tree.dart';
import '../util/util.dart';
// TODO(johnniwinther): Merge functionality with the `TreePrinter`.
class AstBuilder {
final Token position;
AstBuilder(this.position);
int get charOffset => position.charOffset;
Modifiers modifiers({bool isConst: false,
bool isFinal: false,
bool isStatic: false}) {
List identifiers = [];
int flags = 0;
if (isConst) {
identifiers.add(identifier('const'));
flags |= Modifiers.FLAG_CONST;
}
if (isFinal) {
identifiers.add(identifier('final'));
flags |= Modifiers.FLAG_FINAL;
}
if (isStatic) {
identifiers.add(identifier('static'));
flags |= Modifiers.FLAG_STATIC;
}
return new Modifiers.withFlags(
new NodeList(null, linkedList(identifiers), null, ''),
flags);
}
Token keywordToken(String text) {
return new KeywordToken(Keyword.keywords[text], position.charOffset);
}
Token stringToken(String text) {
return new StringToken.fromString(IDENTIFIER_INFO, text, charOffset);
}
Token symbolToken(PrecedenceInfo info) {
return new SymbolToken(info, charOffset);
}
Identifier identifier(String text) {
Keyword keyword = Keyword.keywords[text];
Token token;
if (keyword != null) {
token = new KeywordToken(Keyword.keywords[text], charOffset);
} else {
token = stringToken(text);
}
return new Identifier(token);
}
Link linkedList(List elements) {
LinkBuilder builder = new LinkBuilder();
elements.forEach((e) => builder.addLast(e));
return builder.toLink();
}
NodeList argumentList(List<Node> nodes) {
return new NodeList(symbolToken(OPEN_PAREN_INFO),
linkedList(nodes),
symbolToken(CLOSE_PAREN_INFO),
',');
}
Return returnStatement(Expression expression) {
return new Return(
keywordToken('return'),
symbolToken(SEMICOLON_INFO),
expression);
}
FunctionExpression functionExpression(Modifiers modifiers,
String name,
NodeList argumentList,
Statement body,
[TypeAnnotation returnType]) {
return new FunctionExpression(
identifier(name),
argumentList,
body,
returnType,
modifiers,
null, // Initializer.
null, // get/set.
null // Async modifier.
);
}
EmptyStatement emptyStatement() {
return new EmptyStatement(symbolToken(COMMA_INFO));
}
LiteralInt literalInt(int value) {
return new LiteralInt(stringToken('$value'), null);
}
LiteralString literalString(String text,
{String prefix: '"',
String suffix: '"'}) {
return new LiteralString(stringToken('$prefix$text$suffix'),
new DartString.literal(text));
}
LiteralList listLiteral(List<Node> elements, {bool isConst: false}) {
return new LiteralList(
null,
new NodeList(symbolToken(OPEN_SQUARE_BRACKET_INFO),
linkedList(elements),
symbolToken(CLOSE_SQUARE_BRACKET_INFO),
','),
isConst ? keywordToken('const') : null);
}
Node createDefinition(Identifier name, Expression initializer) {
if (initializer == null) return name;
return new SendSet(null, name, new Operator(symbolToken(EQ_INFO)),
new NodeList.singleton(initializer));
}
VariableDefinitions initializingFormal(String fieldName) {
return new VariableDefinitions.forParameter(
new NodeList.empty(),
null,
Modifiers.EMPTY,
new NodeList.singleton(
new Send(identifier('this'), identifier(fieldName))));
}
NewExpression newExpression(String typeName,
NodeList arguments,
{bool isConst: false}) {
return new NewExpression(keywordToken(isConst ? 'const' : 'new'),
new Send(null, identifier(typeName), arguments));
}
Send reference(Identifier identifier) {
return new Send(null, identifier);
}
Send indexGet(Expression receiver, Expression index) {
return new Send(receiver,
new Operator(symbolToken(INDEX_INFO)),
new NodeList.singleton(index));
}
LiteralMapEntry mapLiteralEntry(Expression key, Expression value) {
return new LiteralMapEntry(key, symbolToken(COLON_INFO), value);
}
LiteralMap mapLiteral(List<LiteralMapEntry> entries, {bool isConst: false}) {
return new LiteralMap(
null, // Type arguments.
new NodeList(symbolToken(OPEN_CURLY_BRACKET_INFO),
linkedList(entries),
symbolToken(CLOSE_CURLY_BRACKET_INFO),
','),
isConst ? keywordToken('const') : null);
}
}
class EnumCreator {
final Compiler compiler;
final EnumClassElementX enumClass;
EnumCreator(this.compiler, this.enumClass);
void createMembers() {
Enum node = enumClass.node;
InterfaceType enumType = enumClass.thisType;
AstBuilder builder = new AstBuilder(enumClass.position);
InterfaceType intType = compiler.intClass.computeType(compiler);
InterfaceType stringType = compiler.stringClass.computeType(compiler);
EnumFieldElementX addInstanceMember(String name, InterfaceType type) {
Identifier identifier = builder.identifier(name);
VariableList variableList =
new VariableList(builder.modifiers(isFinal: true));
variableList.type = type;
EnumFieldElementX variable = new EnumFieldElementX(
identifier, enumClass, variableList, identifier);
enumClass.addMember(variable, compiler);
return variable;
}
EnumFieldElementX indexVariable = addInstanceMember('index', intType);
VariableDefinitions indexDefinition = builder.initializingFormal('index');
FunctionExpression constructorNode = builder.functionExpression(
builder.modifiers(isConst: true),
enumClass.name,
builder.argumentList([indexDefinition]),
builder.emptyStatement());
EnumConstructorElementX constructor = new EnumConstructorElementX(
enumClass,
builder.modifiers(isConst: true),
constructorNode);
EnumFormalElementX indexFormal = new EnumFormalElementX(
constructor,
indexDefinition,
builder.identifier('index'),
indexVariable);
FunctionSignatureX constructorSignature = new FunctionSignatureX(
requiredParameters: [indexFormal],
requiredParameterCount: 1,
type: new FunctionType(constructor, const VoidType(),
<DartType>[intType]));
constructor.functionSignatureCache = constructorSignature;
enumClass.addMember(constructor, compiler);
List<FieldElement> enumValues = <FieldElement>[];
VariableList variableList =
new VariableList(builder.modifiers(isStatic: true, isConst: true));
variableList.type = enumType;
int index = 0;
List<Node> valueReferences = <Node>[];
List<LiteralMapEntry> mapEntries = <LiteralMapEntry>[];
for (Link<Node> link = node.names.nodes;
!link.isEmpty;
link = link.tail) {
Identifier name = link.head;
AstBuilder valueBuilder = new AstBuilder(name.token);
// Add reference for the `values` field.
valueReferences.add(valueBuilder.reference(name));
// Add map entry for `toString` implementation.
mapEntries.add(valueBuilder.mapLiteralEntry(
valueBuilder.literalInt(index),
valueBuilder.literalString('${enumClass.name}.${name.source}')));
Expression initializer = valueBuilder.newExpression(
enumClass.name,
valueBuilder.argumentList([valueBuilder.literalInt(index)]),
isConst: true);
SendSet definition = valueBuilder.createDefinition(name, initializer);
EnumFieldElementX field = new EnumFieldElementX(
name, enumClass, variableList, definition, initializer);
enumValues.add(field);
enumClass.addMember(field, compiler);
index++;
}
VariableList valuesVariableList =
new VariableList(builder.modifiers(isStatic: true, isConst: true));
InterfaceType listType = compiler.listClass.computeType(compiler);
valuesVariableList.type = listType.createInstantiation([enumType]);
Identifier valuesIdentifier = builder.identifier('values');
// TODO(johnniwinther): Add type argument.
Expression initializer = builder.listLiteral(
valueReferences, isConst: true);
Node definition = builder.createDefinition(valuesIdentifier, initializer);
EnumFieldElementX valuesVariable = new EnumFieldElementX(
valuesIdentifier, enumClass, valuesVariableList,
definition, initializer);
enumClass.addMember(valuesVariable, compiler);
// TODO(johnniwinther): Support return type. Note `String` might be prefixed
// or not imported within the current library.
FunctionExpression toStringNode = builder.functionExpression(
Modifiers.EMPTY,
'toString',
builder.argumentList([]),
builder.returnStatement(
builder.indexGet(
builder.mapLiteral(mapEntries, isConst: true),
builder.reference(builder.identifier('index')))
)
);
EnumMethodElementX toString = new EnumMethodElementX('toString',
enumClass, Modifiers.EMPTY, toStringNode);
FunctionSignatureX toStringSignature = new FunctionSignatureX(
type: new FunctionType(toString, stringType));
toString.functionSignatureCache = toStringSignature;
enumClass.addMember(toString, compiler);
enumClass.enumValues = enumValues;
}
}