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}