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 faux hyponymy (i.e. matching 011 * referents whose type has a name that is equal to the simple name that acts as 012 * definite expression plus a non-empty prefix). 013 * 014 * <p> 015 * TODO: Reformulate the definition of faux hyponymy in a stricter form that 016 * does not cover features prefixing the conceptual type. 017 * </p> 018 * 019 * @param <N> The node type in the AST 020 * @param <E> The expression type 021 * @param <TB> The type binding type 022 * @param <S> The scope type (optional) 023 * @param <I> The type used to represent identifiers 024 * @param <QI> The type used to represent qualified identifiers 025 * @param <EV> The type of the event contained in the condition that is 026 * evaluated to check when the perspectivations shall be applied. 027 * @param <PP> The type used for positions that carry perspectivations 028 */ 029public class FauxHyponymy<N, E, TB, S, I, QI, EV, PP> 030 extends AbstractConceptReferentializationStrategy<N, E, TB, S, I, QI, EV, PP> { 031 032 public static final String HyFx_KIND = "HyFx"; 033 034 /** 035 * Used in contract testing. 036 */ 037 @SuppressWarnings("unused") 038 protected FauxHyponymy() { 039 } 040 041 public FauxHyponymy(final AnaphorsSpi<N, E, TB, S, I, QI, EV, PP> anaphorsSpi) { 042 super(anaphorsSpi); 043 } 044 045 private boolean canReferToInternal(final Referent<TB, S, I, QI> potentialReferent, final S scope, 046 final Predicate<TB> comparison) { 047 final TB typeOfPotentialReferent = potentialReferent.resolveType(scope); 048 // TODO: should cache type binding / use resolved type 049 // TODO: Need to test cases in which multiple types with identical 050 // simple name 051 // are available in the compilation unit 052 return comparison.test(typeOfPotentialReferent); 053 } 054 055 /** 056 * Returns true, if the given definite expression is a simple name, and the 057 * simple name is equal to a true suffix of the simple name of the type of the 058 * referent. (True suffix means that there is a non-empty prefix before the 059 * suffix.) 060 * 061 * @param idFromDefiniteExpression the ID from the definite expression that 062 * shall refer 063 * @param potentialReferent the potential referent of the definite 064 * expression 065 * @param scope the scope in which the definite expression 066 * occurs 067 * @return {@code true}, if the definite expression is a simple name that is 068 * equal to the simple name of the type of the referent, {@code false} 069 * otherwise. 070 * @see #isCaseSensitive() 071 * @see #canReferToUsingConceptualType(Object, Referent, Object) 072 */ 073 @Override 074 public boolean canReferTo(final I idFromDefiniteExpression, final Referent<TB, S, I, QI> potentialReferent, 075 final S scope) { 076 // TODO: Rename 077 // nameOfIdentifierEqualsFauxHyponymOfSimpleNameOfTypeBinding to 078 // nameOfIdentifierEqualsFauxHyponymOfSimpleNameOfType 079 return canReferToInternal(potentialReferent, scope, 080 typeOfPotentialReferent -> anaphorsSpi.nameOfIdentifierEqualsFauxHyponymOfSimpleNameOfTypeBinding( 081 idFromDefiniteExpression, typeOfPotentialReferent, isCaseSensitive())); 082 } 083 084 /** 085 * Returns true, if the given definite expression is a simple name, and the 086 * conceptual type expressed in the simple name is equal to a true suffix of the 087 * simple name of the type of the referent. (True suffix means that there is a 088 * non-empty prefix before the suffix.) 089 * 090 * @param idFromDefiniteExpression the ID from the definite expression that 091 * shall refer 092 * @param potentialReferent the potential referent of the definite 093 * expression 094 * @param scope the scope in which the definite expression 095 * occurs 096 * @return {@code true}, if the definite expression is a simple name that is 097 * equal to the simple name of the type of the referent, {@code false} 098 * otherwise. 099 * @see #isCaseSensitive() 100 * @see #canReferTo(Object, Referent, Object) 101 */ 102 @Override 103 public boolean canReferToUsingConceptualType(final I idFromDefiniteExpression, 104 final Referent<TB, S, I, QI> potentialReferent, final S scope) { 105 return canReferToInternal(potentialReferent, scope, 106 typeOfPotentialReferent -> anaphorsSpi.conceptualTypeInIdentifierEqualsFauxHyponymyOfSimpleNameOfType( 107 idFromDefiniteExpression, typeOfPotentialReferent, isCaseSensitive())); 108 } 109 110 @Override 111 public FeatureContainer<QI> getFeaturesRemainingInIdentifierIfItCanReferUsingConceptualType( 112 final I idFromDefiniteExpression, final Referent<TB, S, I, QI> potentialReferent, final S scope) { 113 // TODO: This implementation actually performs a number of checks twice 114 // in canReferToUsingConceptualType and 115 // spi.getFeaturesRemainingInIdentifierBesidesConceptualTypeOfReferentName 116 // . It should be replaced by one that implements all checks in 117 // spi.getFeaturesRemainingInIdentifierBesidesConceptualTypeOfReferentName 118 // so that canReferToUsingConceptualType does not need to be invoked. 119 if (canReferToUsingConceptualType(idFromDefiniteExpression, potentialReferent, scope)) { 120 final TB typeOfPotentialReferent = potentialReferent.resolveType(scope); 121 return anaphorsSpi.getFeaturesRemainingInIdentifierBesidesConceptualTypeOfReferentTypeWithFauxHyponymy( 122 idFromDefiniteExpression, typeOfPotentialReferent, isCaseSensitive()); 123 } 124 return null; 125 } 126 127 /** 128 * Whether or not type names are matched in a case-sensitive way. 129 * 130 * @return false 131 */ 132 protected boolean isCaseSensitive() { 133 return false; 134 } 135 136 @Override 137 public String getKind() { 138 return HyFx_KIND; 139 } 140}