001package de.monochromata.anaphors.ast.reference.strategy.concept; 002 003import java.util.function.Predicate; 004 005import de.monochromata.anaphors.ast.feature.FeatureContainer; 006import de.monochromata.anaphors.ast.reference.Referent; 007import de.monochromata.anaphors.ast.spi.AnaphorsSpi; 008 009/** 010 * Referentialization based on case-insensitive exact type recurrence. 011 * 012 * @param <N> The node type in the AST 013 * @param <E> The expression type 014 * @param <TB> The type binding type 015 * @param <S> The scope type (optional) 016 * @param <I> The type used to represent identifiers 017 * @param <QI> The type used to represent qualified identifiers 018 * @param <EV> The type of the event contained in the condition that is 019 * evaluated to check when the perspectivations shall be applied. 020 * @param <PP> The type used for positions that carry perspectivations 021 */ 022public class TypeRecurrence<N, E, TB, S, I, QI, EV, PP> 023 extends AbstractConceptReferentializationStrategy<N, E, TB, S, I, QI, EV, PP> { 024 025 public static final String Rt_KIND = "Rt"; 026 027 /** 028 * Used in contract testing. 029 */ 030 @SuppressWarnings("unused") 031 protected TypeRecurrence() { 032 } 033 034 public TypeRecurrence(final AnaphorsSpi<N, E, TB, S, I, QI, EV, PP> anaphorsSpi) { 035 super(anaphorsSpi); 036 } 037 038 private boolean canReferToInternal(final Referent<TB, S, I, QI> potentialReferent, final S scope, 039 final Predicate<TB> comparison) { 040 final TB typeOfPotentialReferent = potentialReferent.resolveType(scope); 041 // TODO: should cache type binding / use resolved type 042 // TODO: Need to test cases in which multiple types with identical 043 // simple name are available in the compilation unit 044 return typeOfPotentialReferent != null && comparison.test(typeOfPotentialReferent); 045 } 046 047 /** 048 * Returns true, if the given definite expression is a simple name, and the 049 * simple name is equal to the simple name of the type of the referent. 050 * 051 * @param idFromDefiniteExpression the ID from the definite expression that 052 * shall refer to the given potential referent 053 * @param potentialReferent the potential referent of the definite 054 * expression 055 * @param scope the scope in which the definite expression 056 * occurs 057 * @return {@code true}, if the definite expression is a simple name that is 058 * equal to the simple name of the type of the referent, {@code false} 059 * otherwise. 060 * @see #isCaseSensitive() 061 * @see #canReferToUsingConceptualType(Object, Referent, Object) 062 */ 063 @Override 064 public boolean canReferTo(final I idFromDefiniteExpression, final Referent<TB, S, I, QI> potentialReferent, 065 final S scope) { 066 return canReferToInternal(potentialReferent, scope, 067 typeOfPotentialReferent -> anaphorsSpi.nameOfIdentifierEqualsSimpleNameOfTypeBinding( 068 idFromDefiniteExpression, typeOfPotentialReferent, isCaseSensitive())); 069 } 070 071 /** 072 * Returns true, if the given definite expression is a simple name, and the 073 * conceptual type expressed in simple name is equal to the simple name of the 074 * type of the referent. 075 * 076 * @param idFromDefiniteExpression the ID from the definite expression that 077 * shall refer 078 * @param potentialReferent the potential referent of the definite 079 * expression 080 * @param scope the scope in which the definite expression 081 * occurs 082 * @return {@code true}, if the definite expression is a simple name that is 083 * equal to the simple name of the type of the referent, {@code false} 084 * otherwise. 085 * @see #isCaseSensitive() 086 * @see #canReferTo(Object, Referent, Object) 087 */ 088 @Override 089 public boolean canReferToUsingConceptualType(final I idFromDefiniteExpression, 090 final Referent<TB, S, I, QI> potentialReferent, final S scope) { 091 return canReferToInternal(potentialReferent, scope, 092 typeOfPotentialReferent -> anaphorsSpi.conceptualTypeInIdentifierEqualsSimpleNameOfType( 093 idFromDefiniteExpression, typeOfPotentialReferent, isCaseSensitive())); 094 } 095 096 @Override 097 public FeatureContainer<QI> getFeaturesRemainingInIdentifierIfItCanReferUsingConceptualType( 098 final I idFromDefiniteExpression, final Referent<TB, S, I, QI> potentialReferent, final S scope) { 099 // TODO: This implementation actually performs a number of checks twice 100 // in canReferToUsingConceptualType and 101 // spi.getFeaturesRemainingInIdentifierBesidesConceptualTypeOfReferentName 102 // . It should be replaced by one that implements all checks in 103 // spi.getFeaturesRemainingInIdentifierBesidesConceptualTypeOfReferentName 104 // so that canReferToUsingConceptualType does not need to be invoked. 105 if (canReferToUsingConceptualType(idFromDefiniteExpression, potentialReferent, scope)) { 106 final TB typeOfPotentialReferent = potentialReferent.resolveType(scope); 107 return anaphorsSpi.getFeaturesRemainingInIdentifierBesidesConceptualTypeOfReferentType( 108 idFromDefiniteExpression, typeOfPotentialReferent, isCaseSensitive()); 109 } 110 return null; 111 } 112 113 /** 114 * Whether or not type names are matched in a case-sensitive way. 115 * 116 * @return false 117 */ 118 protected boolean isCaseSensitive() { 119 return false; 120 } 121 122 @Override 123 public String getKind() { 124 return Rt_KIND; 125 } 126}