| /******************************************************************************* |
| * Copyright (c) 2008-2016 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 |
| * Antonio Garcia-Dominguez - aggregate into select(...) |
| ******************************************************************************/ |
| package org.eclipse.epsilon.evl.dom; |
| |
| import java.util.*; |
| import org.eclipse.epsilon.common.module.IModule; |
| import org.eclipse.epsilon.common.parse.AST; |
| import org.eclipse.epsilon.common.util.AstUtil; |
| import org.eclipse.epsilon.eol.dom.AnnotatableModuleElement; |
| import org.eclipse.epsilon.eol.dom.ExecutableBlock; |
| import org.eclipse.epsilon.eol.dom.IExecutableModuleElement; |
| import org.eclipse.epsilon.eol.dom.TypeExpression; |
| 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.function.CheckedEolPredicate; |
| import org.eclipse.epsilon.eol.types.EolModelElementType; |
| import org.eclipse.epsilon.evl.execute.context.IEvlContext; |
| import org.eclipse.epsilon.evl.parse.EvlParser; |
| |
| public class ConstraintContext extends AnnotatableModuleElement implements IExecutableModuleElement { |
| |
| protected final ArrayList<Constraint> constraints = new ArrayList<>(); |
| protected TypeExpression typeExpression; |
| protected ExecutableBlock<Boolean> guardBlock; |
| protected EolModelElementType type; |
| /** |
| * @since 1.6 |
| */ |
| protected Boolean isLazy; |
| |
| @SuppressWarnings("unchecked") |
| public void build(AST cst, IModule module) { |
| super.build(cst, module); |
| |
| typeExpression = (TypeExpression) module.createAst(cst.getFirstChild(), this); |
| guardBlock = (ExecutableBlock<Boolean>) module.createAst(AstUtil.getChild(cst, EvlParser.GUARD), this); |
| |
| List<AST> constraintASTs = AstUtil.getChildren(cst, EvlParser.CONSTRAINT, EvlParser.CRITIQUE); |
| constraints.ensureCapacity(constraintASTs.size()); |
| |
| for (AST constraintAst : constraintASTs) { |
| Constraint constraint = (Constraint) module.createAst(constraintAst, this); |
| constraint.setConstraintContext(this); |
| constraints.add(constraint); |
| } |
| } |
| |
| /** |
| * |
| * @param modelElement |
| * @param context |
| * @return |
| * @throws EolRuntimeException |
| * @since 1.6 |
| */ |
| public boolean shouldBeChecked(Object modelElement, IEvlContext context) throws EolRuntimeException { |
| return !isLazy(context) && appliesTo(modelElement, context, false); |
| } |
| |
| public boolean appliesTo(Object object, IEvlContext context) throws EolRuntimeException { |
| return appliesTo(object, context, false); |
| } |
| |
| public boolean appliesTo(Object object, IEvlContext context, boolean checkType) throws EolRuntimeException { |
| if (checkType && !context.getModelRepository().getOwningModel(object).isOfType(object, getTypeName())) |
| return false; |
| |
| if (guardBlock != null) |
| return guardBlock.execute(context, Variable.createReadOnlyVariable("self", object)); |
| |
| return true; |
| } |
| |
| /** |
| * An entire context is lazy if all constraints are lazy, or if it is |
| * itself marked as lazy. |
| * @throws EolRuntimeException |
| */ |
| public boolean isLazy(IEvlContext context) throws EolRuntimeException { |
| if (isLazy == null) { |
| isLazy = getBooleanAnnotationValue("lazy", context) || |
| constraints.stream() |
| .allMatch((CheckedEolPredicate<Constraint>) c -> c.isLazy(context)); |
| } |
| return isLazy; |
| } |
| |
| public String getTypeName() { |
| return typeExpression != null ? typeExpression.getName() : null; |
| } |
| |
| public ArrayList<Constraint> getConstraints() { |
| return constraints; |
| } |
| |
| public TypeExpression getTypeExpression() { |
| return typeExpression; |
| } |
| |
| public void setTypeExpression(TypeExpression typeExpression) { |
| this.typeExpression = typeExpression; |
| } |
| |
| public Collection<?> getAllOfSourceType(IEvlContext context) |
| throws EolModelElementTypeNotFoundException, EolModelNotFoundException { |
| return getType(context).getAllOfType(); |
| } |
| |
| public Collection<?> getAllOfSourceKind(IEvlContext context) |
| throws EolModelElementTypeNotFoundException, EolModelNotFoundException { |
| return getType(context).getAllOfKind(); |
| } |
| |
| public EolModelElementType getType(IEvlContext context) throws EolModelNotFoundException, EolModelElementTypeNotFoundException { |
| if (type == null) { |
| type = new EolModelElementType(getTypeName(), context); |
| } |
| return type; |
| } |
| |
| /** |
| * Executes all constraints for the given model element, provided it is applicable to this |
| * ConstraintContext and that this ConstraintContext is not lazy. |
| * @param constraintsToCheck The constraints, which may be a subset of this ConstraintContext's children. |
| * @param modelElement The model element object. |
| * @param context The execution context. |
| * @throws EolRuntimeException |
| * @since 1.6 |
| */ |
| public void execute(Collection<Constraint> constraintsToCheck, Object modelElement, IEvlContext context) throws EolRuntimeException { |
| if (shouldBeChecked(modelElement, context)) { |
| for (Constraint constraint : constraintsToCheck) { |
| constraint.execute(modelElement, context); |
| } |
| } |
| } |
| |
| /** |
| * Executes all of the give constraints for all applicable elements of this type. |
| * @param constraintsToCheck The Constraints, which may be a subset of this ConstraintContext's children. |
| * @param context The execution context. |
| * @throws EolRuntimeException |
| * @see {@link #execute(Collection, Object, IEvlContext)} |
| * @since 1.6 |
| */ |
| public void execute(Collection<Constraint> constraintsToCheck, IEvlContext context) throws EolRuntimeException { |
| if (!isLazy(context)) { |
| for (Object modelElement : getAllOfSourceKind(context)) { |
| if (appliesTo(modelElement, context, false)) { |
| for (Constraint constraint : constraintsToCheck) { |
| constraint.execute(modelElement, context); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Executes all of this ConstraintContext's constraints for the given element. |
| * @param modelElement The model element object. |
| * @param context The execution context. |
| * @throws EolRuntimeException |
| * @see {@link #execute(Collection, Object, IEvlContext)} |
| * @since 1.6 |
| */ |
| public void execute(Object modelElement, IEvlContext context) throws EolRuntimeException { |
| execute(getConstraints(), modelElement, context); |
| } |
| |
| /** |
| * Checks all of this ConstraintContext's constraints for all applicable elements of this type. |
| * @param context_ The EVL execution context. |
| * @throws EolRuntimeException |
| * @return nothing. |
| * @see {@link #execute(Collection, Object, IEvlContext)} |
| * @since 1.6 |
| */ |
| @Override |
| public Void execute(IEolContext context_) throws EolRuntimeException { |
| IEvlContext context = (IEvlContext) context_; |
| Collection<Constraint> constraintsToCheck = getConstraints(); |
| for (Object element : getAllOfSourceKind(context)) { |
| execute(constraintsToCheck, element, context); |
| } |
| return null; |
| } |
| |
| @Override |
| public String toString() { |
| return getTypeName(); |
| } |
| |
| /** |
| * @since 1.6 |
| */ |
| @Override |
| public int hashCode() { |
| return Objects.hash(super.hashCode(), getTypeName(), constraints.size()); |
| } |
| |
| /** |
| * @since 1.6 |
| */ |
| @Override |
| public boolean equals(Object other) { |
| if (!super.equals(other)) |
| return false; |
| |
| ConstraintContext cc = (ConstraintContext) other; |
| return |
| Objects.equals(this.getTypeName(), cc.getTypeName()) && |
| this.constraints.size() == cc.constraints.size(); |
| } |
| } |