blob: 85534aaf66fe8db00ed0b20c9419706d2b5d2582 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008-2019 The University of York.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* Contributors:
* Dimitrios Kolovos - initial API and implementation
* Sina Madani - bug #538175
******************************************************************************/
package org.eclipse.epsilon.eol.types;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import org.eclipse.epsilon.common.module.ModuleElement;
import org.eclipse.epsilon.common.util.CollectionUtil;
import org.eclipse.epsilon.eol.IEolModule;
import org.eclipse.epsilon.eol.compile.m3.MetaClass;
import org.eclipse.epsilon.eol.exceptions.EolRuntimeException;
import org.eclipse.epsilon.eol.exceptions.models.EolModelElementTypeNotFoundException;
import org.eclipse.epsilon.eol.exceptions.models.EolModelNotFoundException;
import org.eclipse.epsilon.eol.execute.context.IEolContext;
import org.eclipse.epsilon.eol.execute.context.Variable;
import org.eclipse.epsilon.eol.models.IModel;
import org.eclipse.epsilon.eol.models.ModelRepository;
import org.eclipse.epsilon.eol.models.ModelRepository.AmbiguityCheckResult;
public class EolModelElementType extends EolType {
protected String modelName = "";
protected String typeName = "";
protected IEolModule module;
protected ModelRepository modelRepo;
protected MetaClass metaClass;
protected IModel cachedModelRef;
public EolModelElementType(MetaClass metaClass) {
this.metaClass = metaClass;
this.typeName = metaClass.getName();
}
public EolModelElementType(String modelAndMetaClass) {
if (modelAndMetaClass.contains("!")) {
String[] parts = modelAndMetaClass.split("!");
modelName = parts[0];
typeName = parts[1];
} else {
modelName = "";
typeName = modelAndMetaClass;
}
}
public EolModelElementType(String modelAndMetaClass, IEolContext context) throws EolModelNotFoundException, EolModelElementTypeNotFoundException {
this(modelAndMetaClass);
this.module = (IEolModule) context.getModule();
checkAmbiguityOfType(context);
getModel(true); // Eager caching, possibly prevents race conditions
}
private void checkAmbiguityOfType(IEolContext context) {
if (modelName.isEmpty()) {
final AmbiguityCheckResult result = context.getModelRepository().checkAmbiguity(typeName);
if (result.isAmbiguous) {
issueAmbiguousTypeWarning(context, result);
}
}
}
private void issueAmbiguousTypeWarning(IEolContext context, AmbiguityCheckResult result) {
final String potentialTypes = CollectionUtil.join(result.namesOfOwningModels, " ", element -> "'" + element + "!" + typeName+"'");
context.getWarningStream().println("Warning: The type '" + typeName + "' " +
"is ambiguous and could refer to any of the following: " + potentialTypes + ". " +
"The type '" + result.nameOfSelectedModel + "!" + typeName + "' has been assumed. " +
determineLocation(context.getFrameStack().getCurrentStatement()));
}
private static String determineLocation(ModuleElement statement) {
if (statement == null)
return "";
else
return "(" + statement.getFile() + "@" + statement.getRegion().getStart().getLine() + ":"
+ statement.getRegion().getStart().getColumn() + ")";
}
public String getModelName() {
return modelName;
}
public void setModelName(String model) {
this.modelName = model;
}
public String getTypeName() {
return typeName;
}
public void setTypeName(String type) {
this.typeName = type;
}
public Collection<?> getAllOfKind() {
try {
return getModel().getAllOfKind(typeName);
}
catch (EolModelElementTypeNotFoundException ex) {
ex.printStackTrace();
return Collections.emptyList();
}
}
public Collection<?> getAllOfType() {
try {
return getModel().getAllOfType(typeName);
}
catch (EolModelElementTypeNotFoundException ex) {
ex.printStackTrace();
return Collections.emptyList();
}
}
public Collection<?> getAll() {
return getAllOfKind();
}
public Collection<?> all() {
return getAllOfKind();
}
public Collection<?> getAllInstances() {
return getAllOfKind();
}
public Collection<?> allInstances() {
return getAllOfKind();
}
public boolean isInstantiable() throws EolModelElementTypeNotFoundException {
return getModel().isInstantiable(typeName);
}
@Override
public boolean isType(Object o) {
try {
return getModel().isOfType(o, typeName);
}
catch (EolModelElementTypeNotFoundException ex) {
ex.printStackTrace();
return false;
}
}
@Override
public Object createInstance() throws EolRuntimeException {
return getModel().createInstance(typeName);
}
@Override
public Object createInstance(List<Object> parameters) throws EolRuntimeException {
return getModel().createInstance(typeName, parameters);
}
@Override
public boolean isKind(Object o) {
try {
return getModel().isOfKind(o, typeName);
}
catch (EolModelElementTypeNotFoundException ex) {
ex.printStackTrace();
return false;
}
}
@Override
public String getName() {
String name = "";
if (!modelName.isEmpty()) {
name = modelName + "!";
}
return name + typeName;
}
public IModel getModel() throws EolModelElementTypeNotFoundException {
return getModel(module.getContext().getModelRepository() != modelRepo);
}
/**
* Fetches the model from the module's context.
*
* @param updateCached Whether to re-acquire reference to the model and model repository.
* @return The model
* @throws EolModelElementTypeNotFoundException
* @since 1.6
*/
public IModel getModel(boolean updateCached) throws EolModelElementTypeNotFoundException {
if (cachedModelRef == null || updateCached) {
modelRepo = module.getContext().getModelRepository();
try {
cachedModelRef = modelRepo.getModelByName(modelName);
}
catch (EolModelNotFoundException ex) {
Variable modelVariable = module.getContext().getFrameStack().get(modelName);
if (modelVariable != null && modelVariable.getValue() instanceof IModel) {
cachedModelRef = (IModel) modelVariable.getValue();
}
}
if (cachedModelRef == null || !cachedModelRef.hasType(typeName)) {
throw new EolModelElementTypeNotFoundException(modelName, typeName);
}
}
return cachedModelRef;
}
public MetaClass getMetaClass() {
return metaClass;
}
public void setMetaClass(MetaClass metaClass) {
this.metaClass = metaClass;
}
@Override
public String toString() {
return getName();
}
@Override
public int hashCode() {
return Objects.hash(
super.hashCode(),
getName(),
module,
metaClass != null ? metaClass.getName() : metaClass
);
}
@Override
public boolean equals(Object other) {
boolean eq = super.equals(other);
if (!eq) return false;
EolModelElementType eme = (EolModelElementType) other;
eq = Objects.equals(this.getName(), eme.getName());
if (eq && !(this.metaClass == null && eme.metaClass == null)) {
if (this.metaClass == null || eme.metaClass == null)
return false;
eq = Objects.equals(this.metaClass.getName(), eme.metaClass.getName());
}
eq = eq && Objects.equals(this.module, eme.module);
return eq;
}
}