001package de.monochromata.anaphors.ast.chain; 002 003import static java.util.Collections.emptyList; 004import static java.util.Collections.singletonList; 005 006import java.util.List; 007 008import de.monochromata.anaphors.ast.ASTBasedAnaphora; 009import de.monochromata.anaphors.ast.AnaphorPart; 010import de.monochromata.anaphors.ast.RelatedExpressionPart; 011import de.monochromata.anaphors.ast.relatedexp.RelatedExpression; 012 013/** 014 * Used to form chains of anaphors. A chain element can have a single 015 * predecessor and multiple successors. I.e. an anaphor can have a single 016 * related expression and a related expression can have multiple related 017 * expressions. 018 * <p> 019 * E.g. 020 * 021 * <pre> 022 * {@code new String("hello"); println(helloString); println(helloString);} 023 * </pre> 024 * 025 * would be realized as three {@link ChainElement}s: 026 * 027 * <pre> 028 * {@code ChainElement(RelatedExpressionPart) 029 * ├ ChainElement(AnaphorPart #1) 030 * └ ChainElement(AnaphorPart #2)} 031 * </pre> 032 * <p> 033 * This 1:N relationship between related expressions and anaphors reflects their 034 * realization via local variables. From a theoretical, linguistic point it 035 * might also suitable to consider the second anaphor to be related to the first 036 * anaphor instead of being related to the (initial) related expression. From a 037 * cognitive point in three-level semantics, the related expression and the two 038 * anaphors would refer to a single node in memory and order would occur 039 * temporally only in the order of reading. 040 * <p> 041 * While an {@link ASTBasedAnaphora} combines both a 042 * {@link RelatedExpressionPart} and a {@link AnaphorPart}, an anaphoric chain 043 * represents them as two {@link ChainElement}s. That way, a two 044 * {@link AnaphorPart}s that are related to the same 045 * {@link RelatedExpressionPart} can be represented as three 046 * {@link ChainElement}s. 047 * 048 * @param <N> The node type in the AST 049 * @param <E> The expression type 050 * @param <T> The type type 051 * @param <B> The binding type 052 * @param <TB> The type binding type 053 * @param <S> The scope type (optional) 054 * @param <I> The type used to represent identifiers 055 * @param <QI> The type used to represent qualified identifiers 056 * @param <AT> The type used for attachments to chain elements that have an 057 * anaphor part. The attachment may be used to stored e.g. an old 058 * anaphora relation. 059 * @param <R> The sub-type of related expression to use 060 * @param <A> The sub-type of AST-based anaphora to use 061 * @param <C> The sub-type of chain element to use 062 */ 063public class ChainElement<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>> { 064 065 public final C previous; 066 public final List<C> next; 067 068 public final RelatedExpressionPart<N, E, T, B, TB, S, I, QI, R> relatedExpression; 069 public final AnaphorPart<N, E, T, B, TB, S, I, QI, R, A> anaphor; 070 071 public final AT anaphorAttachment; 072 073 /** 074 * Used in contract testing. 075 */ 076 @SuppressWarnings("unused") 077 protected ChainElement() { 078 this(null, null, null, null, null); 079 } 080 081 public ChainElement(final C previous, final AnaphorPart<N, E, T, B, TB, S, I, QI, R, A> anaphor, 082 final AT anaphorAttachment) { 083 this(previous, emptyList(), null, anaphor, anaphorAttachment); 084 } 085 086 public ChainElement(final C next, final RelatedExpressionPart<N, E, T, B, TB, S, I, QI, R> relatedExpression) { 087 this(null, singletonList(next), relatedExpression, null, null); 088 } 089 090 public ChainElement(final List<C> next, 091 final RelatedExpressionPart<N, E, T, B, TB, S, I, QI, R> relatedExpression) { 092 this(null, next, relatedExpression, null, null); 093 } 094 095 public ChainElement(final C previous, final List<C> next, 096 final RelatedExpressionPart<N, E, T, B, TB, S, I, QI, R> relatedExpression, 097 final AnaphorPart<N, E, T, B, TB, S, I, QI, R, A> anaphor, final AT anaphorAttachment) { 098 this.previous = previous; 099 this.next = next; 100 this.relatedExpression = relatedExpression; 101 this.anaphor = anaphor; 102 this.anaphorAttachment = anaphorAttachment; 103 } 104 105 @Override 106 public int hashCode() { 107 final int prime = 31; 108 int result = 1; 109 result = prime * result + ((anaphor == null) ? 0 : anaphor.hashCode()); 110 result = prime * result + ((anaphorAttachment == null) ? 0 : anaphorAttachment.hashCode()); 111 result = prime * result + ((relatedExpression == null) ? 0 : relatedExpression.hashCode()); 112 return result; 113 } 114 115 @Override 116 public boolean equals(final Object obj) { 117 if (this == obj) { 118 return true; 119 } 120 if (obj == null) { 121 return false; 122 } 123 if (getClass() != obj.getClass()) { 124 return false; 125 } 126 final ChainElement other = (ChainElement) obj; 127 if (anaphor == null) { 128 if (other.anaphor != null) { 129 return false; 130 } 131 } else if (!anaphor.equals(other.anaphor)) { 132 return false; 133 } 134 if (anaphorAttachment == null) { 135 if (other.anaphorAttachment != null) { 136 return false; 137 } 138 } else if (!anaphorAttachment.equals(other.anaphorAttachment)) { 139 return false; 140 } 141 if (relatedExpression == null) { 142 if (other.relatedExpression != null) { 143 return false; 144 } 145 } else if (!relatedExpression.equals(other.relatedExpression)) { 146 return false; 147 } 148 return true; 149 } 150 151 @Override 152 public String toString() { 153 return "ChainElement [relatedExpression=" + relatedExpression + ", anaphor=" + anaphor + ", attachment=" 154 + anaphorAttachment + "]"; 155 } 156 157}