001package de.monochromata.anaphors.ast.chain; 002 003import static java.util.Collections.emptyList; 004import static java.util.Collections.singletonList; 005import static java.util.stream.Collectors.toList; 006 007import java.util.ArrayList; 008import java.util.List; 009import java.util.concurrent.atomic.AtomicBoolean; 010import java.util.stream.Collectors; 011import java.util.stream.Stream; 012 013import org.apache.commons.lang3.tuple.ImmutablePair; 014import org.apache.commons.lang3.tuple.Pair; 015 016import de.monochromata.anaphors.ast.ASTBasedAnaphora; 017import de.monochromata.anaphors.ast.AnaphorPart; 018import de.monochromata.anaphors.ast.RelatedExpressionPart; 019import de.monochromata.anaphors.ast.relatedexp.RelatedExpression; 020 021/** 022 * Used to maintain a list of anaphoric chains. 023 * 024 * {@link ChainElement} 025 */ 026public interface Chaining { 027 028 /** 029 * @param <N> The node type in the AST 030 * @param <E> The expression type 031 * @param <T> The type type 032 * @param <B> The binding type 033 * @param <TB> The type binding type 034 * @param <S> The scope type (optional) 035 * @param <I> The type used to represent identifiers 036 * @param <QI> The type used to represent qualified identifiers 037 * @param <AT> The type used for attachments to chain elements that have an 038 * anaphor part. The attachment may be used to stored e.g. an old 039 * anaphora relation. 040 * @param <R> The sub-type of related expression to use 041 * @param <A> The sub-type of AST-based anaphora to use 042 * @param <C> The sub-type of chain element to use 043 */ 044 static <N, E, T, B, TB extends B, S, I, QI, AT, R extends RelatedExpression<N, T, B, TB, S, QI, R>, A extends ASTBasedAnaphora<N, E, T, B, TB, S, I, QI, R, A>, C extends ChainElement<N, E, T, B, TB, S, I, QI, AT, R, A, C>> List<C> emptyListOfChains() { 045 return emptyList(); 046 } 047 048 static <N, E, T, B, TB extends B, S, I, QI, AT, R extends RelatedExpression<N, T, B, TB, S, QI, R>, A extends ASTBasedAnaphora<N, E, T, B, TB, S, I, QI, R, A>, C extends ChainElement<N, E, T, B, TB, S, I, QI, AT, R, A, C>> List<C> singletonListOfChains( 049 final A anaphora, final AT anaphorAttachment, 050 final ChainElementFactory<N, E, T, B, TB, S, I, QI, AT, R, A, C> factory) { 051 return singletonList(toChain(anaphora, anaphorAttachment, factory)); 052 } 053 054 static <N, E, T, B, TB extends B, S, I, QI, AT, R extends RelatedExpression<N, T, B, TB, S, QI, R>, A extends ASTBasedAnaphora<N, E, T, B, TB, S, I, QI, R, A>, C extends ChainElement<N, E, T, B, TB, S, I, QI, AT, R, A, C>> C toChain( 055 final A anaphora, final AT anaphorAttachment, 056 final ChainElementFactory<N, E, T, B, TB, S, I, QI, AT, R, A, C> factory) { 057 return toChain(anaphora.getRelatedExpressionPart(), anaphora.getAnaphorPart(), anaphorAttachment, factory); 058 } 059 060 static <TB extends B, PP, E, T, I, B, QI, EV, N, S, AT, R extends RelatedExpression<N, T, B, TB, S, QI, R>, A extends ASTBasedAnaphora<N, E, T, B, TB, S, I, QI, R, A>, C extends ChainElement<N, E, T, B, TB, S, I, QI, AT, R, A, C>> C toChain( 061 final RelatedExpressionPart<N, E, T, B, TB, S, I, QI, R> relatedExpressionPart, 062 final AnaphorPart<N, E, T, B, TB, S, I, QI, R, A> anaphorPart, final AT anaphorAttachment, 063 final ChainElementFactory<N, E, T, B, TB, S, I, QI, AT, R, A, C> factory) { 064 final List<C> nextElements = new ArrayList<>(); 065 final C relatedExpressionElement = factory.create(null, nextElements, relatedExpressionPart, null, null); 066 final C nextElement = factory.create(relatedExpressionElement, new ArrayList<>(), null, anaphorPart, 067 anaphorAttachment); 068 nextElements.add(nextElement); 069 return relatedExpressionElement; 070 } 071 072 static <N, E, T, B, TB extends B, S, I, QI, AT, R extends RelatedExpression<N, T, B, TB, S, QI, R>, A extends ASTBasedAnaphora<N, E, T, B, TB, S, I, QI, R, A>, C extends ChainElement<N, E, T, B, TB, S, I, QI, AT, R, A, C>> List<C> merge( 073 final List<C> existingChains, final A anaphora, final AT anaphorAttachment, 074 final ChainElementFactory<N, E, T, B, TB, S, I, QI, AT, R, A, C> factory) { 075 return merge(existingChains, toChain(anaphora, anaphorAttachment, factory), factory); 076 } 077 078 static <N, E, T, B, TB extends B, S, I, QI, AT, R extends RelatedExpression<N, T, B, TB, S, QI, R>, A extends ASTBasedAnaphora<N, E, T, B, TB, S, I, QI, R, A>, C extends ChainElement<N, E, T, B, TB, S, I, QI, AT, R, A, C>> List<C> merge( 079 final List<C> existingChains, final List<C> newChains, 080 final ChainElementFactory<N, E, T, B, TB, S, I, QI, AT, R, A, C> factory) { 081 List<C> result = existingChains; 082 for (final C newChain : newChains) { 083 result = merge(result, newChain, factory); 084 } 085 return result; 086 } 087 088 static <N, E, T, B, TB extends B, S, I, QI, AT, R extends RelatedExpression<N, T, B, TB, S, QI, R>, A extends ASTBasedAnaphora<N, E, T, B, TB, S, I, QI, R, A>, C extends ChainElement<N, E, T, B, TB, S, I, QI, AT, R, A, C>> List<C> merge( 089 final List<C> existingChains, final C newChain, 090 final ChainElementFactory<N, E, T, B, TB, S, I, QI, AT, R, A, C> factory) { 091 final Pair<Boolean, List<C>> mergedAndResult = mergeForEqualRelatedExpression(existingChains, newChain, 092 factory); 093 if (mergedAndResult.getLeft()) { 094 return mergedAndResult.getRight(); 095 } 096 return addChain(existingChains, newChain); 097 } 098 099 static <N, E, T, B, TB extends B, S, I, QI, AT, R extends RelatedExpression<N, T, B, TB, S, QI, R>, A extends ASTBasedAnaphora<N, E, T, B, TB, S, I, QI, R, A>, C extends ChainElement<N, E, T, B, TB, S, I, QI, AT, R, A, C>> Pair<Boolean, List<C>> mergeForEqualRelatedExpression( 100 final List<C> existingChains, final C newChain, 101 final ChainElementFactory<N, E, T, B, TB, S, I, QI, AT, R, A, C> factory) { 102 final AtomicBoolean ruleApplied = new AtomicBoolean(false); 103 final List<C> mappedChains = existingChains.stream() 104 .map(existingChainElement -> mergeForEqualRelatedExpression(existingChainElement, newChain, ruleApplied, 105 factory)) 106 .collect(toList()); 107 return new ImmutablePair<>(ruleApplied.get(), mappedChains); 108 } 109 110 static <N, E, T, B, TB extends B, S, I, QI, AT, R extends RelatedExpression<N, T, B, TB, S, QI, R>, A extends ASTBasedAnaphora<N, E, T, B, TB, S, I, QI, R, A>, C extends ChainElement<N, E, T, B, TB, S, I, QI, AT, R, A, C>> C mergeForEqualRelatedExpression( 111 final C existingRoot, final C newRoot, final AtomicBoolean ruleApplied, 112 final ChainElementFactory<N, E, T, B, TB, S, I, QI, AT, R, A, C> factory) { 113 if (relatedExpressionsAreEqual(existingRoot, newRoot)) { 114 final C mergedChain = mergeByRelatedExpression(existingRoot, newRoot, factory); 115 ruleApplied.set(true); 116 return mergedChain; 117 } 118 return existingRoot; 119 } 120 121 static <N, E, T, B, TB extends B, S, I, QI, AT, R extends RelatedExpression<N, T, B, TB, S, QI, R>, A extends ASTBasedAnaphora<N, E, T, B, TB, S, I, QI, R, A>, C extends ChainElement<N, E, T, B, TB, S, I, QI, AT, R, A, C>> boolean relatedExpressionsAreEqual( 122 final C existingRoot, final C newRoot) { 123 return existingRoot.relatedExpression.getRelatedExpression().getRelatedExpression() 124 .equals(newRoot.relatedExpression.getRelatedExpression().getRelatedExpression()); 125 } 126 127 static <N, E, T, B, TB extends B, S, I, QI, AT, R extends RelatedExpression<N, T, B, TB, S, QI, R>, A extends ASTBasedAnaphora<N, E, T, B, TB, S, I, QI, R, A>, C extends ChainElement<N, E, T, B, TB, S, I, QI, AT, R, A, C>> C mergeByRelatedExpression( 128 final C existingRoot, final C newRoot, 129 final ChainElementFactory<N, E, T, B, TB, S, I, QI, AT, R, A, C> factory) { 130 final List<C> next = new ArrayList<>(); 131 next.addAll(existingRoot.next); 132 next.addAll(linkToPrevious(newRoot.next, existingRoot, factory)); 133 return factory.create(null, next, existingRoot.relatedExpression, null, null); 134 } 135 136 static <N, E, T, B, TB extends B, S, I, QI, AT, R extends RelatedExpression<N, T, B, TB, S, QI, R>, A extends ASTBasedAnaphora<N, E, T, B, TB, S, I, QI, R, A>, C extends ChainElement<N, E, T, B, TB, S, I, QI, AT, R, A, C>> List<C> linkToPrevious( 137 final List<C> nextElements, final C previous, 138 final ChainElementFactory<N, E, T, B, TB, S, I, QI, AT, R, A, C> factory) { 139 return nextElements.stream().map(next -> factory.create(previous, linkToPrevious(next.next, next, factory), 140 next.relatedExpression, next.anaphor, next.anaphorAttachment)).collect(Collectors.toList()); 141 } 142 143 static <N, E, T, B, TB extends B, S, I, QI, AT, R extends RelatedExpression<N, T, B, TB, S, QI, R>, A extends ASTBasedAnaphora<N, E, T, B, TB, S, I, QI, R, A>, C extends ChainElement<N, E, T, B, TB, S, I, QI, AT, R, A, C>> List<C> addChain( 144 final List<C> existingChains, final C newChain) { 145 return Stream.concat(existingChains.stream(), Stream.of(newChain)).collect(toList()); 146 } 147 148}