001package de.monochromata.anaphors.ast.chain;
002
003import static java.util.Collections.singletonList;
004import static java.util.stream.Collectors.toList;
005
006import java.util.List;
007import java.util.function.Predicate;
008import java.util.stream.Stream;
009import java.util.stream.Stream.Builder;
010
011import de.monochromata.anaphors.ast.ASTBasedAnaphora;
012import de.monochromata.anaphors.ast.relatedexp.RelatedExpression;
013
014public interface ChainTraversal {
015
016        /**
017         * @param <N>  The node type in the AST
018         * @param <E>  The expression type
019         * @param <T>  The type type
020         * @param <B>  The binding 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 <AT> The type used for attachments to chain elements that have an
026         *             anaphor part. The attachment may be used to stored e.g. an old
027         *             anaphora relation.
028         * @param <R>  The sub-type of related expression to use
029         * @param <A>  The sub-type of AST-based anaphora to use
030         * @param <C>  The sub-type of chain element to use
031         * @throws IllegalStateException If no anaphor element could be found.
032         */
033        static <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>> List<C> getAnaphorElementsForRelatedExpressionElement(
034                        final C relatedExpressionElement) {
035                final Builder<C> builder = Stream.builder();
036                collectAnaphorElements(relatedExpressionElement.next, builder, next -> next.anaphor != null,
037                                next -> next.relatedExpression == null);
038                final List<C> anaphorElements = builder.build().collect(toList());
039                if (anaphorElements.isEmpty()) {
040                        throw new IllegalStateException("No anaphor elements found");
041                }
042                return anaphorElements;
043        }
044
045        /**
046         * @param <N>  The node type in the AST
047         * @param <E>  The expression type
048         * @param <T>  The type type
049         * @param <B>  The binding type
050         * @param <TB> The type binding type
051         * @param <S>  The scope type (optional)
052         * @param <I>  The type used to represent identifiers
053         * @param <QI> The type used to represent qualified identifiers
054         * @param <AT> The type used for attachments to chain elements that have an
055         *             anaphor part. The attachment may be used to stored e.g. an old
056         *             anaphora relation.
057         * @param <R>  The sub-type of related expression to use
058         * @param <A>  The sub-type of AST-based anaphora to use
059         * @param <C>  The sub-type of chain element to use
060         * @throws IllegalStateException If no related expression element could be
061         *                               found.
062         */
063        static <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>> C getRelatedExpressionElementForAnaphorElement(
064                        final C anaphorElement) {
065                C current = anaphorElement;
066                while (current != null) {
067                        if (current.relatedExpression != null) {
068                                return current;
069                        }
070                        current = current.previous;
071                }
072                throw new IllegalStateException("No related expression element found");
073        }
074
075        /**
076         * @param <N>  The node type in the AST
077         * @param <E>  The expression type
078         * @param <T>  The type type
079         * @param <B>  The binding type
080         * @param <TB> The type binding type
081         * @param <S>  The scope type (optional)
082         * @param <I>  The type used to represent identifiers
083         * @param <QI> The type used to represent qualified identifiers
084         * @param <AT> The type used for attachments to chain elements that have an
085         *             anaphor part. The attachment may be used to stored e.g. an old
086         *             anaphora relation.
087         * @param <R>  The sub-type of related expression to use
088         * @param <A>  The sub-type of AST-based anaphora to use
089         * @param <C>  The sub-type of chain element to use
090         */
091        static <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>> Stream<C> getRelatedExpressionElements(
092                        final C root) {
093                return getElements(root, next -> next.relatedExpression != null);
094        }
095
096        /**
097         * @param <N>  The node type in the AST
098         * @param <E>  The expression type
099         * @param <T>  The type type
100         * @param <B>  The binding type
101         * @param <TB> The type binding type
102         * @param <S>  The scope type (optional)
103         * @param <I>  The type used to represent identifiers
104         * @param <QI> The type used to represent qualified identifiers
105         * @param <AT> The type used for attachments to chain elements that have an
106         *             anaphor part. The attachment may be used to stored e.g. an old
107         *             anaphora relation.
108         * @param <R>  The sub-type of related expression to use
109         * @param <A>  The sub-type of AST-based anaphora to use
110         * @param <C>  The sub-type of chain element to use
111         */
112        static <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>> Stream<C> getAnaphorElements(
113                        final C root) {
114                return getElements(root, next -> next.anaphor != null);
115        }
116
117        /**
118         * @param <N>  The node type in the AST
119         * @param <E>  The expression type
120         * @param <T>  The type type
121         * @param <B>  The binding type
122         * @param <TB> The type binding type
123         * @param <S>  The scope type (optional)
124         * @param <I>  The type used to represent identifiers
125         * @param <QI> The type used to represent qualified identifiers
126         * @param <AT> The type used for attachments to chain elements that have an
127         *             anaphor part. The attachment may be used to stored e.g. an old
128         *             anaphora relation.
129         * @param <R>  The sub-type of related expression to use
130         * @param <A>  The sub-type of AST-based anaphora to use
131         * @param <C>  The sub-type of chain element to use
132         */
133        static <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>> Stream<C> getElements(
134                        final C root, final Predicate<C> predicate) {
135                final Builder<C> builder = Stream.builder();
136                collectAnaphorElements(singletonList(root), builder, predicate);
137                return builder.build();
138        }
139
140        /**
141         * @param <N>  The node type in the AST
142         * @param <E>  The expression type
143         * @param <T>  The type type
144         * @param <B>  The binding type
145         * @param <TB> The type binding type
146         * @param <S>  The scope type (optional)
147         * @param <I>  The type used to represent identifiers
148         * @param <QI> The type used to represent qualified identifiers
149         * @param <AT> The type used for attachments to chain elements that have an
150         *             anaphor part. The attachment may be used to stored e.g. an old
151         *             anaphora relation.
152         * @param <R>  The sub-type of related expression to use
153         * @param <A>  The sub-type of AST-based anaphora to use
154         * @param <C>  The sub-type of chain element to use
155         */
156        static <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>> void collectAnaphorElements(
157                        final List<C> nextElements, final Builder<C> builder, final Predicate<C> predicate) {
158                collectAnaphorElements(nextElements, builder, predicate, unused -> true);
159        }
160
161        /**
162         * @param <N>  The node type in the AST
163         * @param <E>  The expression type
164         * @param <T>  The type type
165         * @param <B>  The binding type
166         * @param <TB> The type binding type
167         * @param <S>  The scope type (optional)
168         * @param <I>  The type used to represent identifiers
169         * @param <QI> The type used to represent qualified identifiers
170         * @param <AT> The type used for attachments to chain elements that have an
171         *             anaphor part. The attachment may be used to stored e.g. an old
172         *             anaphora relation.
173         * @param <R>  The sub-type of related expression to use
174         * @param <A>  The sub-type of AST-based anaphora to use
175         * @param <C>  The sub-type of chain element to use
176         */
177        static <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>> void collectAnaphorElements(
178                        final List<C> nextElements, final Builder<C> builder, final Predicate<C> shouldAddElement,
179                        final Predicate<C> shouldContinue) {
180                for (final C next : nextElements) {
181                        if (shouldAddElement.test(next)) {
182                                builder.add(next);
183                        }
184                        if (shouldContinue.test(next)) {
185                                collectAnaphorElements(next.next, builder, shouldAddElement);
186                        }
187                }
188        }
189
190}