/**
* Copyright 2004-2016 Riccardo Solmi. All rights reserved.
* This file is part of the Whole Platform.
*
* The Whole Platform is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Whole Platform is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the Whole Platform. If not, see <http://www.gnu.org/licenses/>.
*/
package org.whole.gen.lang.model.impl;
import java.util.List;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.ReturnStatement;
import org.eclipse.jdt.core.dom.SwitchStatement;
import org.eclipse.jdt.core.dom.TryStatement;
import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword;
import org.whole.gen.CompilationUnitBuilder;
import org.whole.gen.lang.LanguageGenerator;
import org.whole.lang.model.AbstractSimpleEntity;
import org.whole.lang.model.IEntity;
import org.whole.lang.reflect.EntityDescriptor;
import org.whole.lang.util.StringUtils;
/**
* @author Riccardo Solmi
*/
public class SimpleEntityImplBuilder extends CompilationUnitBuilder {
public MethodDeclaration fieldsConstructor;
private MethodDeclaration getByIndexMethod;
private List getByIndexSwitchStatements;
private MethodDeclaration setByIndexMethod;
private List setByIndexSwitchStatements;
private MethodDeclaration hashCodeMethod;
private MethodDeclaration equalsMethod;
private MethodDeclaration toStringMethod;
private int featureIndex;
private int children;
private int references;
public SimpleEntityImplBuilder(LanguageGenerator generator, String packageSuffix, String entityName) {
super(generator, packageSuffix);
addClassDeclaration(generator.entityImplName(entityName), AbstractSimpleEntity.class.getName());
generator.putEntity(entityName);
// addImportDeclaration(generator.modelPackage(), true);
addSuperInterface(generator.entityInterfaceQName(entityName));
addSerialVersionUID(1L);
// add wGetEntityDescriptor method
MethodDeclaration methodDecl = newMethodDeclaration(
newParameterizedType(EntityDescriptor.class.getName(), generator.entityInterfaceQName(entityName)),
"wGetEntityDescriptor");
methodDecl.getBody().statements().add(newReturnStatement(newFieldAccess(generator.specificEntityDescriptorEnumName(), entityName)));
addBodyDeclaration(methodDecl);
// add wGetEntityOrd method
methodDecl = newMethodDeclaration("int", "wGetEntityOrd");
methodDecl.getBody().statements().add(newReturnStatement(newFieldAccess(generator.specificEntityDescriptorEnumName(), entityName+"_ord")));
addBodyDeclaration(methodDecl);
// add accept method
addBodyDeclaration(newAcceptMethod(generator.specificVisitorInterfaceName()));
}
private MethodDeclaration getByIndexMethod() {
if (getByIndexMethod == null) {
getByIndexMethod = newMethodDeclaration(IEntity.class.getName(), "wGet");
getByIndexMethod.parameters().add(newSingleVariableDeclaration("int", "index"));
}
return getByIndexMethod;
}
private void getByIndexMethodEnd() {
if (getByIndexMethod == null)
return;
getByIndexSwitchStatements.add(newDefaultCaseStatement());
getByIndexSwitchStatements.add(newThrowStatement(newClassInstanceCreation("IllegalArgumentException")));
addBodyDeclaration(getByIndexMethod);
}
private MethodDeclaration setByIndexMethod() {
if (setByIndexMethod == null) {
setByIndexMethod = newMethodDeclaration("void", "wSet");
setByIndexMethod.parameters().add(newSingleVariableDeclaration("int", "index"));
setByIndexMethod.parameters().add(newSingleVariableDeclaration(IEntity.class.getName(), "value"));
}
return setByIndexMethod;
}
private void setByIndexMethodEnd() {
if (setByIndexMethod == null)
return;
setByIndexSwitchStatements.add(newDefaultCaseStatement());
setByIndexSwitchStatements.add(newThrowStatement(newClassInstanceCreation("IllegalArgumentException")));
addBodyDeclaration(setByIndexMethod);
}
private MethodDeclaration hashCodeMethod(Expression exp) {
if (hashCodeMethod == null) {
hashCodeMethod = newMethodDeclaration("int", "wHashCode");
hashCodeMethod.getBody().statements().add(newReturnStatement(exp));
addBodyDeclaration(hashCodeMethod);
} else {
ReturnStatement stm = (ReturnStatement) hashCodeMethod.getBody().statements().get(0);
Expression oldExp = stm.getExpression();
stm.setExpression(null);
stm.setExpression(newInfixExpression(oldExp, "+", newInfixExpression(newLiteral(29), "*", exp)));
}
return hashCodeMethod;
}
private void hashCodeMethodAddId(String fType, String fName) {
hashCodeMethod(
newMethodInvocation(
newMethodInvocation(StringUtils.getterName(fName)),
"wHashCode"));
}
private MethodDeclaration equalsMethod(Expression exp) {
if (equalsMethod == null) {
equalsMethod = newMethodDeclaration("boolean", "wEquals", newSingleVariableDeclaration(IEntity.class.getName(), "entity"));
equalsMethod.getBody().statements().add(
newIfStatement(newInfixExpression(ast.newThisExpression(), "==", ast.newSimpleName("entity")),
newReturnStatement(newLiteral(true))));
equalsMethod.getBody().statements().add(
newIfStatement(newPrefixExpression(
newMethodInvocation(
newMethodInvocation("wGetEntityDescriptor"), "equals",
newMethodInvocation("entity", "wGetEntityDescriptor")), "!"),
newReturnStatement(newLiteral(false))));
equalsMethod.getBody().statements().add(
newTryStatement(newReturnStatement(exp),
newSingleVariableDeclaration("Exception", "e"),
newReturnStatement(newLiteral(false))));
addBodyDeclaration(equalsMethod);
} else {
TryStatement tryStm = (TryStatement) equalsMethod.getBody().statements().get(2);
ReturnStatement stm = (ReturnStatement) tryStm.getBody().statements().get(0);
Expression oldExp = stm.getExpression();
stm.setExpression(null);
stm.setExpression(newInfixExpression(oldExp, "&&", exp));
}
return equalsMethod;
}
private void equalsMethodAddId(String fType, String fName) {
equalsMethod(
newMethodInvocation(
newMethodInvocation(StringUtils.getterName(fType, fName)),
"wEquals",
newMethodInvocation("entity", "wGet",
newFieldAccess(((LanguageGenerator) generator).specificFeatureDescriptorEnumName(), fName))));
}
private MethodDeclaration toStringMethod() {
if (toStringMethod == null) {
toStringMethod = newMethodDeclaration("void", "toString", newSingleVariableDeclaration(StringBuffer.class.getName(), "buffer"));
toStringMethod.modifiers().remove(0);//assume ModifierKeyword.PUBLIC_KEYWORD
toStringMethod.modifiers().add(ast.newModifier(ModifierKeyword.PROTECTED_KEYWORD));
addBodyDeclaration(toStringMethod);
}
return toStringMethod;
}
private void toStringMethodAddField(String fType, String fName) {
List body = toStringMethod().getBody().statements();
body.add(newExpressionStatement(newMethodInvocation(
"buffer",
"append",
newLiteral(fName+"="))));
body.add(newExpressionStatement(newMethodInvocation(
"buffer",
"append",
ast.newSimpleName(fName))));
}
public void endBody() {
if (children > 0 || references > 0) {
getByIndexMethodEnd();
setByIndexMethodEnd();
}
// add byIndex and size methods
if (children > 0) {
MethodDeclaration method = newMethodDeclaration("int", "wSize");
method.getBody().statements().add(newReturnStatement(newLiteral(children)));
addBodyDeclaration(method);
}
// add outAdjacentSize method
if (references > 0) {
MethodDeclaration method = newMethodDeclaration("int", "wAdjacentSize");
method.getBody().statements().add(newReturnStatement(newLiteral(references)));
addBodyDeclaration(method);
}
}
public void addField(String fType, String fName, String name, boolean isId, boolean isOptional, boolean isReference, boolean isShared, boolean isDerived) {
// if (StringUtils.isAmbiguous(fType))
if (!StringUtils.isPrimitiveOrString(fType))
addImportDeclaration(generator.modelPackage()+"."+fType);
if (isId) {
hashCodeMethodAddId(fType, fName);
equalsMethodAddId(fType, fName);
toStringMethodAddField(fType, fName);
}
// add field, getter and setter methods
addBodyDeclaration(newFieldDeclaration(fType, fName));
addBodyDeclaration(newGetterMethodWithNotification(((LanguageGenerator) generator).specificFeatureDescriptorEnumName(), fType, fName, name));
addBodyDeclaration(newSetterMethodWithNotification(((LanguageGenerator) generator).specificFeatureDescriptorEnumName(), fType, fName, name, isReference));
// if (fieldsConstructor == null)
// addBodyDeclaration(1, fieldsConstructor = newConstructorDeclaration(typeDec));
// addConstructorCase(fieldsConstructor, fType, fName);
if (StringUtils.isPrimitiveOrString(fType))
return;
// add get(int index) case
if (getByIndexMethod().getBody().statements().size() == 0) {
SwitchStatement switchStm = newSwitchStatement(ast.newSimpleName("index"));
getByIndexMethod().getBody().statements().add(switchStm);
getByIndexSwitchStatements = switchStm.statements();
}
getByIndexSwitchStatements.add(newCaseStatement(newLiteral(featureIndex)));
getByIndexSwitchStatements.add(newReturnStatement(newMethodInvocation(
newMethodInvocation(StringUtils.getterName(StringUtils.isJavaKeyword(name) ? name : fName)), "wGetAdaptee", newLiteral(false))));
// add set(int index, IEntity value) case
if (setByIndexMethod().getBody().statements().size() == 0) {
SwitchStatement switchStm = newSwitchStatement(ast.newSimpleName("index"));
setByIndexMethod().getBody().statements().add(switchStm);
setByIndexSwitchStatements = switchStm.statements();
}
setByIndexSwitchStatements.add(newCaseStatement(newLiteral(featureIndex)));
MethodInvocation callExp = newMethodInvocation(StringUtils.setterName(StringUtils.isJavaKeyword(name) ? name : fName),
newMethodInvocation(ast.newSimpleName("value"), "wGetAdapter",
newFieldAccess(((LanguageGenerator) generator).specificEntityDescriptorEnumName(), fType)));
setByIndexSwitchStatements.add(newExpressionStatement(callExp));
setByIndexSwitchStatements.add(ast.newBreakStatement());
featureIndex++;
if (isReference)
references++;
else
children++;
}
}