/*
* ******************************************************************************
* MontiCore Language Workbench
* Copyright (c) 2015, MontiCore, All rights reserved.
*
* This project 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.0 of the License, or (at your option) any later version.
* This library 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 this project. If not, see <http://www.gnu.org/licenses/>.
* ******************************************************************************
*/
package de.monticore.symboltable.types;
import com.google.common.collect.ImmutableList;
import de.monticore.symboltable.CommonScopeSpanningSymbol;
import de.monticore.symboltable.MutableScope;
import de.monticore.symboltable.modifiers.BasicAccessModifier;
import de.monticore.symboltable.types.references.JTypeReference;
import de.se_rwth.commons.logging.Log;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Strings.isNullOrEmpty;
import static de.monticore.symboltable.Symbols.sortSymbolsByPosition;
/**
*
* @author Pedram Mir Seyed Nazari
* @param <T>
* @param <S>
*/
public abstract class CommonJTypeSymbol <T extends JTypeSymbol, S extends JFieldSymbol, U extends JMethodSymbol, V extends JTypeReference<T>>
extends CommonScopeSpanningSymbol implements JTypeSymbol {
private final JAttributeSymbolKind attributeKind;
private final JMethodSymbolKind methodKind;
private V superClass;
private final List<V> interfaces = new ArrayList<>();
private boolean isAbstract = false;
private boolean isFinal = false;
private boolean isInterface = false;
private boolean isEnum = false;
private boolean isFormalTypeParameter = false;
// e.g., inner interface or inner class
private boolean isInnerType = false;
protected CommonJTypeSymbol(String name, JTypeSymbolKind typeKind,
JAttributeSymbolKind attributeKind, JMethodSymbolKind methodKind) {
super(name, typeKind);
this.attributeKind = attributeKind;
this.methodKind = methodKind;
}
protected CommonJTypeSymbol(String name) {
this(name, JTypeSymbol.KIND, JFieldSymbol.KIND, JMethodSymbol.KIND);
}
@Override
protected MutableScope createSpannedScope() {
return new CommonJTypeScope(Optional.empty());
}
@Override
public boolean isGeneric() {
return !getFormalTypeParameters().isEmpty();
}
public void addFormalTypeParameter(T formalTypeParameter) {
checkArgument(formalTypeParameter.isFormalTypeParameter());
getMutableSpannedScope().add(formalTypeParameter);
}
@Override
public List<T> getFormalTypeParameters() {
final Collection<T> resolvedTypes = getSpannedScope().resolveLocally(T.KIND);
return resolvedTypes.stream().filter(T::isFormalTypeParameter).collect(Collectors.toList());
}
@Override
public Optional<V> getSuperClass() {
return Optional.ofNullable(superClass);
}
public void setSuperClass(V superClass) {
this.superClass = superClass;
}
@Override
public List<V> getInterfaces() {
return ImmutableList.copyOf(interfaces);
}
public void addInterface(V superInterface) {
this.interfaces.add(Log.errorIfNull(superInterface));
}
@Override
public List<V> getSuperTypes() {
final List<V> superTypes = new ArrayList<>();
if (getSuperClass().isPresent()) {
superTypes.add(getSuperClass().get());
}
superTypes.addAll(getInterfaces());
return superTypes;
}
public void addField(S attribute) {
getMutableSpannedScope().add(Log.errorIfNull(attribute));
}
@Override
public List<S> getFields() {
return sortSymbolsByPosition(getSpannedScope().resolveLocally(attributeKind));
}
@Override
public Optional<S> getField(String attributeName) {
checkArgument(!isNullOrEmpty(attributeName));
return getSpannedScope().resolveLocally(attributeName, attributeKind);
}
public void addMethod(U method) {
Log.errorIfNull(method);
checkArgument(!method.isConstructor());
getMutableSpannedScope().add(method);
}
@Override
public List<U> getMethods() {
final Collection<U> resolvedMethods = getSpannedScope().resolveLocally(methodKind);
final List<U> methods = sortSymbolsByPosition(resolvedMethods.stream().filter(method -> !method.isConstructor()).collect(Collectors.toList()));
return methods;
}
@Override
public Optional<U> getMethod(String methodName) {
checkArgument(!isNullOrEmpty(methodName));
Optional<U> method = getSpannedScope().resolveLocally(methodName, methodKind);
if (method.isPresent() && !method.get().isConstructor()) {
return method;
}
return Optional.empty();
}
public void addConstructor(U constructor) {
Log.errorIfNull(constructor);
checkArgument(constructor.isConstructor());
getMutableSpannedScope().add(constructor);
}
@Override
public List<U> getConstructors() {
final Collection<U> resolvedMethods = getSpannedScope().resolveLocally(methodKind);
final List<U> constructors = sortSymbolsByPosition(resolvedMethods.stream().filter(U::isConstructor).collect(Collectors.toList()));
return constructors;
}
public void addInnerType(T innerType) {
Log.errorIfNull(innerType);
getMutableSpannedScope().add(innerType);
}
@Override
public List<T> getInnerTypes() {
return sortSymbolsByPosition(getSpannedScope().resolveLocally(getKind()));
}
@Override
public Optional<T> getInnerType(String innerTypeName) {
checkArgument(!isNullOrEmpty(innerTypeName));
return getSpannedScope().resolveLocally(innerTypeName, getKind());
}
public void setAbstract(boolean isAbstract) {
this.isAbstract = isAbstract;
}
@Override
public boolean isAbstract() {
return isAbstract;
}
public void setFinal(boolean isFinal) {
this.isFinal = isFinal;
}
@Override
public boolean isFinal() {
return isFinal;
}
public void setInterface(boolean isInterface) {
this.isInterface = isInterface;
}
@Override
public boolean isInterface() {
return isInterface;
}
public void setEnum(boolean isEnum) {
this.isEnum = isEnum;
}
@Override
public boolean isEnum() {
return isEnum;
}
@Override
public boolean isClass() {
return !isInterface() && !isEnum();
}
public void setPrivate() {
setAccessModifier(BasicAccessModifier.PRIVATE);
}
public void setProtected() {
setAccessModifier(BasicAccessModifier.PROTECTED);
}
public void setPublic() {
setAccessModifier(BasicAccessModifier.PUBLIC);
}
@Override
public boolean isPrivate() {
return getAccessModifier().equals(BasicAccessModifier.PRIVATE);
}
@Override
public boolean isProtected() {
return getAccessModifier().equals(BasicAccessModifier.PROTECTED);
}
@Override
public boolean isPublic() {
return getAccessModifier().equals(BasicAccessModifier.PUBLIC);
}
public void setInnerType(boolean innerType) {
isInnerType = innerType;
}
@Override
public boolean isInnerType() {
return isInnerType;
}
/**
* @param formalTypeParameter true, if this type itself is a formal type parameter
*/
public void setFormalTypeParameter(boolean formalTypeParameter) {
this.isFormalTypeParameter = formalTypeParameter;
}
@Override
public boolean isFormalTypeParameter() {
return isFormalTypeParameter;
}
}