001package de.monochromata.anaphors.ast.reference.strategy.concept; 002 003import java.util.List; 004import java.util.Optional; 005import java.util.function.Function; 006import java.util.function.Predicate; 007 008import de.monochromata.anaphors.ast.feature.FeatureContainer; 009import de.monochromata.anaphors.ast.reference.Referent; 010import de.monochromata.anaphors.ast.spi.AnaphorsSpi; 011 012/** 013 * Referentialization based on case-insensitive hyponymy (i.e. matching 014 * referents whose type is a - potentially transitive - super-class or a - 015 * potentially transitively - implemented interface of the type of the definite 016 * expression). 017 * 018 * @param <N> The node type in the AST 019 * @param <E> The expression type 020 * @param <TB> The type binding type 021 * @param <S> The scope type (optional) 022 * @param <I> The type used to represent identifiers 023 * @param <QI> The type used to represent qualified identifiers 024 * @param <EV> The type of the event contained in the condition that is 025 * evaluated to check when the perspectivations shall be applied. 026 * @param <PP> The type used for positions that carry perspectivations 027 */ 028public class Hyponymy<N, E, TB, S, I, QI, EV, PP> 029 extends AbstractConceptReferentializationStrategy<N, E, TB, S, I, QI, EV, PP> { 030 031 public static final String Hy_KIND = "Hy"; 032 033 private final Function<TB, Optional<TB>> getSuperClass; 034 private final Function<TB, List<TB>> getImplementedInterfaces; 035 private final Function<I, Function<TB, Boolean>> nameOfIdentifierEqualsSimpleNameOfTypeBinding; 036 private final Function<I, Function<TB, Boolean>> conceptualTypeInIdentifierEqualsSimpleNameOfTypeBinding; 037 038 /** 039 * Used in contract testing. 040 */ 041 @SuppressWarnings("unused") 042 protected Hyponymy() { 043 this(null, null, null, null); 044 } 045 046 public Hyponymy(final AnaphorsSpi<N, E, TB, S, I, QI, EV, PP> anaphorsSpi, 047 final Function<TB, Optional<TB>> getSuperClass, final Function<TB, List<TB>> getImplementedInterfaces) { 048 this(getSuperClass, getImplementedInterfaces, 049 id -> type -> anaphorsSpi.nameOfIdentifierEqualsSimpleNameOfTypeBinding(id, type, false), 050 id -> type -> anaphorsSpi.conceptualTypeInIdentifierEqualsSimpleNameOfType(id, type, false)); 051 } 052 053 public Hyponymy(final Function<TB, Optional<TB>> getSuperClass, 054 final Function<TB, List<TB>> getImplementedInterfaces, 055 final Function<I, Function<TB, Boolean>> nameOfIdentifierEqualsSimpleNameOfTypeBinding, 056 final Function<I, Function<TB, Boolean>> conceptualTypeInIdentifierEqualsSimpleNameOfTypeBinding) { 057 super(null); 058 this.getSuperClass = getSuperClass; 059 this.getImplementedInterfaces = getImplementedInterfaces; 060 this.nameOfIdentifierEqualsSimpleNameOfTypeBinding = nameOfIdentifierEqualsSimpleNameOfTypeBinding; 061 this.conceptualTypeInIdentifierEqualsSimpleNameOfTypeBinding = conceptualTypeInIdentifierEqualsSimpleNameOfTypeBinding; 062 } 063 064 @Override 065 public boolean canReferTo(final I idFromDefiniteExpression, final Referent<TB, S, I, QI> potentialReferent, 066 final S scope) { 067 return canReferToInternal(potentialReferent, scope, 068 nameOfIdentifierEqualsSimpleNameOfTypeBinding.apply(idFromDefiniteExpression)); 069 } 070 071 private boolean canReferToInternal(final Referent<TB, S, I, QI> potentialReferent, final S scope, 072 final Function<TB, Boolean> comparison) { 073 return canReferToInternal(potentialReferent, scope, (Predicate<TB>) type -> comparison.apply(type)); 074 } 075 076 private boolean canReferToInternal(final Referent<TB, S, I, QI> potentialReferent, final S scope, 077 final Predicate<TB> comparison) { 078 final var canReferToAnImplementedInterface = canReferToAnImplementedInterface(comparison); 079 final var type = potentialReferent.resolveType(scope); 080 final var optionalSuperClass = getSuperClass.apply(type); 081 return canReferToASuperclass(optionalSuperClass, comparison, canReferToAnImplementedInterface) 082 || canReferToAnImplementedInterface.test(type); 083 } 084 085 private boolean canReferToASuperclass(final Optional<TB> optionalSuperClass, 086 final Predicate<TB> canReferUsingSimpleNameOfTypeBinding, 087 final Predicate<TB> canReferToAnImplementedInterface) { 088 if (optionalSuperClass.isEmpty()) { 089 return false; 090 } 091 final var superClass = optionalSuperClass.get(); 092 final var canReferToSuperClass = canReferUsingSimpleNameOfTypeBinding.test(superClass); 093 if (canReferToSuperClass) { 094 return true; 095 } else if (canReferToAnImplementedInterface.test(superClass)) { 096 return true; 097 } 098 // Recurse 099 return canReferToASuperclass(getSuperClass.apply(superClass), canReferUsingSimpleNameOfTypeBinding, 100 canReferToAnImplementedInterface); 101 } 102 103 private Predicate<TB> canReferToAnImplementedInterface(final Predicate<TB> canReferUsingSimpleNameOfTypeBinding) { 104 return type -> { 105 final var implementedInterfaces = getImplementedInterfaces.apply(type); 106 final var canReferToImplementedInterface = implementedInterfaces.stream() 107 .anyMatch(canReferUsingSimpleNameOfTypeBinding); 108 if (canReferToImplementedInterface) { 109 return true; 110 } 111 // Recurse 112 return implementedInterfaces.stream() 113 .anyMatch(canReferToAnImplementedInterface(canReferUsingSimpleNameOfTypeBinding)); 114 }; 115 } 116 117 @Override 118 public boolean canReferToUsingConceptualType(final I idFromDefiniteExpression, 119 final Referent<TB, S, I, QI> potentialReferent, final S scope) { 120 return canReferToInternal(potentialReferent, scope, 121 conceptualTypeInIdentifierEqualsSimpleNameOfTypeBinding.apply(idFromDefiniteExpression)); 122 } 123 124 @Override 125 public FeatureContainer<QI> getFeaturesRemainingInIdentifierIfItCanReferUsingConceptualType( 126 final I idFromDefiniteExpression, final Referent<TB, S, I, QI> potentialReferent, final S scope) { 127 throw new UnsupportedOperationException("Not yet implemented"); 128 } 129 130 @Override 131 public String getKind() { 132 return Hy_KIND; 133 } 134 135}