Index: pkg/compiler/lib/src/resolution/enum_creator.dart |
diff --git a/pkg/compiler/lib/src/resolution/enum_creator.dart b/pkg/compiler/lib/src/resolution/enum_creator.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..fcc179682edea72902cb83327c827a339d076224 |
--- /dev/null |
+++ b/pkg/compiler/lib/src/resolution/enum_creator.dart |
@@ -0,0 +1,267 @@ |
+// 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; |
+ |
+ final Modifiers finalModifiers = |
+ new Modifiers.withFlags(null, Modifiers.FLAG_FINAL); |
+ final Modifiers constModifiers = |
+ new Modifiers.withFlags(null, Modifiers.FLAG_CONST); |
+ final Modifiers staticConstModifiers = |
+ new Modifiers.withFlags(null, |
+ Modifiers.FLAG_STATIC | Modifiers.FLAG_CONST); |
+ |
+ 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)); |
+ } |
+ |
+} |
+ |
+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.finalModifiers); |
+ variableList.type = type; |
+ EnumFieldElementX variable = new EnumFieldElementX( |
+ identifier, enumClass, variableList, identifier); |
+ enumClass.addMember(variable, compiler); |
+ return variable; |
+ } |
+ |
+ EnumFieldElementX indexVariable = addInstanceMember('index', intType); |
+ EnumFieldElementX nameVariable = addInstanceMember('_name', stringType); |
+ |
+ VariableDefinitions indexDefinition = builder.initializingFormal('index'); |
+ VariableDefinitions nameDefinition = builder.initializingFormal('_name'); |
+ |
+ FunctionExpression constructorNode = builder.functionExpression( |
+ builder.constModifiers, |
+ enumClass.name, |
+ builder.argumentList([indexDefinition, nameDefinition]), |
+ builder.emptyStatement()); |
+ |
+ EnumConstructorElementX constructor = new EnumConstructorElementX( |
+ enumClass, |
+ builder.constModifiers, |
+ constructorNode); |
+ |
+ EnumFormalElementX indexFormal = new EnumFormalElementX( |
+ constructor, |
+ indexDefinition, |
+ builder.identifier('index'), |
+ indexVariable); |
+ |
+ EnumFormalElementX nameFormal = new EnumFormalElementX( |
+ constructor, |
+ nameDefinition, |
+ builder.identifier('_name'), |
+ nameVariable); |
+ |
+ FunctionSignatureX constructorSignature = new FunctionSignatureX( |
+ requiredParameters: builder.linkedList([indexFormal, nameFormal]), |
+ requiredParameterCount: 2, |
+ type: new FunctionType(constructor, const VoidType(), |
+ <DartType>[intType, stringType])); |
+ constructor.functionSignatureCache = constructorSignature; |
+ enumClass.addMember(constructor, compiler); |
+ |
+ VariableList variableList = new VariableList(builder.staticConstModifiers); |
+ variableList.type = enumType; |
+ int index = 0; |
+ List<Node> valueReferences = <Node>[]; |
+ for (Link<Node> link = node.names.nodes; |
+ !link.isEmpty; |
+ link = link.tail) { |
+ Identifier name = link.head; |
+ AstBuilder valueBuilder = new AstBuilder(name.token); |
+ valueReferences.add(new Send(null, name)); |
+ |
+ Expression initializer = valueBuilder.newExpression( |
+ enumClass.name, |
+ valueBuilder.argumentList([ |
+ valueBuilder.literalInt(index), |
+ valueBuilder.literalString('${name.source}') |
+ ]), |
+ isConst: true); |
+ SendSet definition = valueBuilder.createDefinition(name, initializer); |
+ |
+ EnumFieldElementX field = new EnumFieldElementX( |
+ name, enumClass, variableList, definition, initializer); |
+ enumClass.addMember(field, compiler); |
+ index++; |
+ } |
+ |
+ VariableList valuesVariableList = |
+ new VariableList(builder.staticConstModifiers); |
+ 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( |
+ new StringInterpolation( |
+ builder.literalString('${enumClass.name}.', suffix: ''), |
+ new NodeList.singleton(new StringInterpolationPart( |
+ new Send(null, builder.identifier('_name')), |
+ builder.literalString('', prefix: ''))) |
+ )) |
+ ); |
+ |
+ 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); |
+ } |
+} |