001package de.monochromata.anaphors.ast.strategy; 002 003import java.util.ArrayList; 004import java.util.Collections; 005import java.util.List; 006import java.util.Optional; 007 008import de.monochromata.AbstractStrategy; 009import de.monochromata.anaphors.ast.ASTBasedAnaphora; 010import de.monochromata.anaphors.ast.reference.Referent; 011import de.monochromata.anaphors.ast.reference.strategy.ReferentializationStrategy; 012import de.monochromata.anaphors.ast.relatedexp.RelatedExpression; 013import de.monochromata.anaphors.ast.relatedexp.strategy.RelatedExpressionStrategy; 014import de.monochromata.anaphors.ast.spi.AnaphoraResolutionSpi; 015import de.monochromata.anaphors.ast.spi.AnaphorsSpi; 016import de.monochromata.anaphors.ast.spi.RelatedExpressionsSpi; 017 018/** 019 * An abstract base class for strategies used to for resolve or construct the 020 * referents of anaphors. 021 * 022 * @param <N> The node type in the AST 023 * @param <E> The expression type 024 * @param <T> The type type 025 * @param <B> The binding type 026 * @param <VB> The variable binding type 027 * @param <FB> The field binding type 028 * @param <MB> The method binding type 029 * @param <TB> The type binding type 030 * @param <S> The scope type (optional) 031 * @param <I> The type used to represent identifiers 032 * @param <QI> The type used to represent qualified identifiers 033 * @param <EV> The type of the event contained in the condition that is 034 * evaluated to check when the perspectivations shall be applied. 035 * @param <PP> The type used for positions that carry perspectivations 036 * @param <R> The sub-type of related expression to use 037 * @param <A> The sub-type of AST-based anaphora to use 038 */ 039public abstract class AbstractAnaphorResolutionStrategy<N, E, T, B, VB extends B, FB extends B, MB extends B, TB extends B, S, I, QI, EV, PP, R extends RelatedExpression<N, T, B, TB, S, QI, R>, A extends ASTBasedAnaphora<N, E, T, B, TB, S, I, QI, R, A>> 040 extends AbstractStrategy implements AnaphorResolutionStrategy<N, E, T, B, TB, S, I, QI, R, A> { 041 042 protected final List<Class<? extends RelatedExpressionStrategy>> supportedRelatedExpressionStrategies; 043 protected final AnaphorsSpi<N, E, TB, S, I, QI, EV, PP> anaphorsSpi; 044 protected final RelatedExpressionsSpi<N, E, T, B, MB, TB, S, I, QI, EV, PP, R> relatedExpressionsSpi; 045 protected final AnaphoraResolutionSpi<N, E, T, B, VB, FB, MB, TB, S, I, QI, R, A> anaphoraResolutionSpi; 046 047 /** 048 * Used in contract testing. 049 */ 050 @SuppressWarnings("unused") 051 protected AbstractAnaphorResolutionStrategy() { 052 this(null, null, null, null); 053 } 054 055 protected AbstractAnaphorResolutionStrategy( 056 final List<Class<? extends RelatedExpressionStrategy>> supportedRelatedExpressionStrategies, 057 final AnaphorsSpi<N, E, TB, S, I, QI, EV, PP> anaphorsSpi, 058 final RelatedExpressionsSpi<N, E, T, B, MB, TB, S, I, QI, EV, PP, R> relatedExpressionsSpi, 059 final AnaphoraResolutionSpi<N, E, T, B, VB, FB, MB, TB, S, I, QI, R, A> anaphoraResolutionSpi) { 060 this.supportedRelatedExpressionStrategies = supportedRelatedExpressionStrategies; 061 this.anaphorsSpi = anaphorsSpi; 062 this.relatedExpressionsSpi = relatedExpressionsSpi; 063 this.anaphoraResolutionSpi = anaphoraResolutionSpi; 064 } 065 066 @Override 067 public boolean canRelateTo( 068 final RelatedExpressionStrategy<N, T, B, TB, S, QI, R> potentialRelatedExpressionStrategy) { 069 return supportedRelatedExpressionStrategies.stream() 070 .anyMatch(supportedType -> supportedType.isInstance(potentialRelatedExpressionStrategy)); 071 } 072 073 @Override 074 public List<A> generatePotentialAnaphora(final S scope, final String anaphor, final E definiteExpression, 075 final List<R> potentialRelatedExpressions, 076 final List<ReferentializationStrategy<E, TB, S, I, QI>> refStrategies) { 077 final List<A> anaphoras = new ArrayList<>(); 078 return getIdForDefiniteExpression(definiteExpression) 079 .map(idFromDefiniteExpression -> generatePotentialAnaphora(scope, anaphor, definiteExpression, 080 potentialRelatedExpressions, refStrategies, anaphoras, idFromDefiniteExpression)) 081 .orElseGet(Collections::emptyList); 082 } 083 084 protected List<A> generatePotentialAnaphora(final S scope, final String anaphor, final E definiteExpression, 085 final List<R> potentialRelatedExpressions, 086 final List<ReferentializationStrategy<E, TB, S, I, QI>> refStrategies, final List<A> anaphoras, 087 final I idFromDefiniteExpression) { 088 // Create anaphora relations for all related expressions 089 // for which at least one referentialization strategy can be applied. 090 for (final R potentialRelatedExpression : potentialRelatedExpressions) { 091 if (canRelateTo(potentialRelatedExpression.getStrategy())) { 092 final List<Referent<TB, S, I, QI>> potentialReferents = createPotentialReferents(scope, 093 potentialRelatedExpression); 094 for (final Referent<TB, S, I, QI> potentialReferent : potentialReferents) { 095 for (final ReferentializationStrategy<E, TB, S, I, QI> refStrategy : refStrategies) { 096 if (refStrategy.canReferTo(idFromDefiniteExpression, potentialReferent, scope)) { 097 anaphoras.add(createAnaphora(scope, anaphor, definiteExpression, potentialRelatedExpression, 098 potentialReferent, refStrategy)); 099 break; 100 } 101 } 102 } 103 } 104 // TODO: Assuming that there is no precedence / hiding 105 } 106 107 return anaphoras; 108 } 109 110 protected Optional<I> getIdForDefiniteExpression(final E definiteExpression) { 111 if (anaphorsSpi.isSimpleName(definiteExpression)) { 112 // cannot resolve type again, since that would trigger anaphor 113 // resolution, too 114 // TODO: Maybe use another approach that also checks visibility etc. 115 return Optional.of(anaphorsSpi.getIdentifierOfSimpleName(definiteExpression)); 116 } else if (couldBeAPreviousRealization(definiteExpression)) { 117 return Optional.of(getIdForPreviousRealization(definiteExpression)); 118 } 119 return Optional.empty(); 120 } 121 122 /** 123 * @return {@literal true} if the given definite expression has been or could 124 * have been created by this or any other 125 * {@link AnaphorResolutionStrategy}. 126 * @see #getIdForPreviousRealization(Object) 127 */ 128 protected boolean couldBeAPreviousRealization(final E definiteExpression) { 129 return anaphoraResolutionSpi.couldBeAPreviousRealization(definiteExpression); 130 } 131 132 /** 133 * Should only be invoked if {@link #couldBeAPreviousRealization(Object)} 134 * returned {@literal true}. 135 * 136 * @see #couldBeAPreviousRealization(Object) 137 */ 138 protected I getIdForPreviousRealization(final E definiteExpression) { 139 return anaphoraResolutionSpi.getIdFromPreviousRealization(definiteExpression); 140 } 141 142 protected abstract List<Referent<TB, S, I, QI>> createPotentialReferents(S scope, R potentialRelatedExpression); 143 144 protected void requireThisAnaphorResolutionStrategy(final A anaphora) { 145 if (anaphora.getAnaphorResolutionStrategy() != this) { 146 throw new IllegalArgumentException("The given anaphora relation was not created by this strategy"); 147 } 148 } 149}