/*
* Copyright (c) 2014, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.dart.engine.internal.builder;
import com.google.dart.engine.ast.EnumConstantDeclaration;
import com.google.dart.engine.ast.EnumDeclaration;
import com.google.dart.engine.ast.NodeList;
import com.google.dart.engine.ast.SimpleIdentifier;
import com.google.dart.engine.ast.visitor.RecursiveAstVisitor;
import com.google.dart.engine.element.FieldElement;
import com.google.dart.engine.element.PropertyAccessorElement;
import com.google.dart.engine.internal.constant.ValidResult;
import com.google.dart.engine.internal.element.ClassElementImpl;
import com.google.dart.engine.internal.element.ConstFieldElementImpl;
import com.google.dart.engine.internal.element.FieldElementImpl;
import com.google.dart.engine.internal.element.PropertyAccessorElementImpl;
import com.google.dart.engine.internal.object.DartObjectImpl;
import com.google.dart.engine.internal.object.GenericState;
import com.google.dart.engine.internal.object.IntState;
import com.google.dart.engine.internal.resolver.TypeProvider;
import com.google.dart.engine.type.InterfaceType;
import com.google.dart.engine.type.Type;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
/**
* Instances of the class {@code EnumMemberBuilder} build the members in enum declarations.
*/
public class EnumMemberBuilder extends RecursiveAstVisitor<Void> {
/**
* The type provider used to access the types needed to build an element model for enum
* declarations.
*/
private TypeProvider typeProvider;
/**
* Initialize a newly created enum member builder.
*
* @param typeProvider the type provider used to access the types needed to build an element model
* for enum declarations
*/
public EnumMemberBuilder(TypeProvider typeProvider) {
this.typeProvider = typeProvider;
}
@Override
public Void visitEnumDeclaration(EnumDeclaration node) {
//
// Finish building the enum.
//
ClassElementImpl enumElement = (ClassElementImpl) node.getName().getStaticElement();
InterfaceType enumType = enumElement.getType();
enumElement.setSupertype(typeProvider.getObjectType());
//
// Populate the fields.
//
ArrayList<FieldElement> fields = new ArrayList<FieldElement>();
ArrayList<PropertyAccessorElement> getters = new ArrayList<PropertyAccessorElement>();
InterfaceType intType = typeProvider.getIntType();
String indexFieldName = "index";
FieldElementImpl indexField = new FieldElementImpl(indexFieldName, -1);
indexField.setFinal(true);
indexField.setSynthetic(true);
indexField.setType(intType);
fields.add(indexField);
getters.add(createGetter(indexField));
FieldElementImpl valuesField = new FieldElementImpl("values", -1);
valuesField.setStatic(true);
valuesField.setConst(true);
valuesField.setSynthetic(true);
valuesField.setType(typeProvider.getListType().substitute(new Type[] {enumType}));
fields.add(valuesField);
getters.add(createGetter(valuesField));
//
// Build the enum constants.
//
NodeList<EnumConstantDeclaration> constants = node.getConstants();
int constantCount = constants.size();
for (int i = 0; i < constantCount; i++) {
SimpleIdentifier constantName = constants.get(i).getName();
FieldElementImpl constantField = new ConstFieldElementImpl(constantName);
constantField.setStatic(true);
constantField.setConst(true);
constantField.setType(enumType);
//
// Create a value for the constant.
//
HashMap<String, DartObjectImpl> fieldMap = new HashMap<String, DartObjectImpl>();
fieldMap.put(indexFieldName, new DartObjectImpl(intType, new IntState(BigInteger.valueOf(i))));
DartObjectImpl value = new DartObjectImpl(enumType, new GenericState(fieldMap));
constantField.setEvaluationResult(new ValidResult(value));
fields.add(constantField);
getters.add(createGetter(constantField));
constantName.setStaticElement(constantField);
}
//
// Finish building the enum.
//
enumElement.setFields(fields.toArray(new FieldElement[fields.size()]));
enumElement.setAccessors(getters.toArray(new PropertyAccessorElement[getters.size()]));
// Client code isn't allowed to invoke the constructor, so we do not model it.
return super.visitEnumDeclaration(node);
}
/**
* Create a getter that corresponds to the given field.
*
* @param field the field for which a getter is to be created
* @return the getter that was created
*/
private PropertyAccessorElement createGetter(FieldElementImpl field) {
PropertyAccessorElementImpl getter = new PropertyAccessorElementImpl(field);
getter.setGetter(true);
getter.setReturnType(field.getType());
field.setGetter(getter);
return getter;
}
}