<commit_before>package org.jamocha.dn.compiler;

import static java.util.stream.Collectors.toCollection;
import static java.util.stream.Collectors.toSet;
import static org.jamocha.util.ToArray.toArray;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

import org.jamocha.dn.ConstructCache.Defrule;
import org.jamocha.dn.ConstructCache.Defrule.TranslatedPath;
import org.jamocha.filter.Path;
import org.jamocha.filter.PathCollector;
import org.jamocha.filter.PathFilter;
import org.jamocha.filter.PathFilter.PathFilterElement;
import org.jamocha.languages.common.ConditionalElement;
import org.jamocha.languages.common.ConditionalElement.AndFunctionConditionalElement;
import org.jamocha.languages.common.ConditionalElement.ExistentialConditionalElement;
import org.jamocha.languages.common.ConditionalElement.InitialFactConditionalElement;
import org.jamocha.languages.common.ConditionalElement.NegatedExistentialConditionalElement;
import org.jamocha.languages.common.ConditionalElement.NotFunctionConditionalElement;
import org.jamocha.languages.common.ConditionalElement.OrFunctionConditionalElement;
import org.jamocha.languages.common.ConditionalElement.SharedConditionalElementWrapper;
import org.jamocha.languages.common.ConditionalElement.TestConditionalElement;
import org.jamocha.languages.common.DefaultConditionalElementsVisitor;
import org.jamocha.languages.common.SingleFactVariable;

/**
 * Collect all PathFilters inside all children of an OrFunctionConditionalElement, returning a List
 * of Lists. Each inner List contains the PathFilters of one child.
 * 
 * @author <NAME> <<EMAIL>>
 * @author <NAME> <<EMAIL>>
 */
@RequiredArgsConstructor
public class PathFilterConsolidator implements DefaultConditionalElementsVisitor {

	private final Defrule rule;
	@Getter
	private List<Defrule.TranslatedPath> translateds = null;

	public List<Defrule.TranslatedPath> consolidate() {
		assert rule.getCondition().getConditionalElements().size() == 1;
		return rule.getCondition().getConditionalElements().get(0).accept(this).translateds;
	}

	@Override
	public void defaultAction(final ConditionalElement ce) {
		// If we are to need the initial fact variable, there should be one within the CE
		final SingleFactVariable initialFactVariable = SomeInitialFactFinder.find(ce);
		// If there is no OrFunctionConditionalElement just proceed with the CE as it were
		// the only child of an OrFunctionConditionalElement.
		translateds =
				Collections.singletonList(NoORsPFC.consolidate(rule, initialFactVariable, ce));
	}

	@Override
	public void visit(final OrFunctionConditionalElement ce) {
		// If we are to need the initial fact variable, there should be one within the CE
		final SingleFactVariable initialFactVariable = SomeInitialFactFinder.find(ce);
		// For each child of the OrCE ...
		this.translateds =
				ce.getChildren().stream().map(child ->
				// ... collect all PathFilters in the child
						NoORsPFC.consolidate(rule, initialFactVariable, child))
						.collect(Collectors.toCollection(ArrayList::new));

	}

	/**
	 * @author <NAME> <<EMAIL>>
	 * @author <NAME> <<EMAIL>>
	 */
	@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
	static class NoORsPFC implements DefaultConditionalElementsVisitor {

		private final SingleFactVariable initialFactVariable;
		private final Map<SingleFactVariable, Path> paths;
		private final boolean negated;

		@Getter
		private List<PathFilter> pathFilters = new ArrayList<>();

		private NoORsPFC(final SingleFactVariable initialFactVariable,
				final Map<SingleFactVariable, Path> paths) {
			this(initialFactVariable, paths, false);
		}

		public static TranslatedPath consolidate(final Defrule rule,
				final SingleFactVariable initialFactVariable, final ConditionalElement ce) {
			final Map<SingleFactVariable, Path> pathMap = FactVariableCollector.collectPaths(ce);
			final NoORsPFC instance = new NoORsPFC(initialFactVariable, pathMap).collect(ce);
			final List<PathFilter> pathFilters = instance.getPathFilters();
			final PathCollector<HashSet<Path>> collector = PathCollector.newHashSet();
			for (final PathFilter filter : pathFilters) {
				collector.collect(filter);
			}
			final Set<Path> unusedPaths = new HashSet<>(pathMap.values());
			unusedPaths.removeAll(collector.getPaths());
			final TranslatedPath translated = rule.newTranslated(pathFilters, pathMap);
			if (unusedPaths.isEmpty()) {
				return translated;
			}
			pathFilters.add(new PathFilter(new PathFilter.DummyPathFilterElement(toArray(
					unusedPaths, Path[]::new))));
			return translated;
		}

		private <T extends ConditionalElement> NoORsPFC collect(final T ce) {
			return ce.accept(this);
		}

		static List<PathFilter> processExistentialCondition(
				final SingleFactVariable initialFactVariable, final ConditionalElement ce,
				final Map<SingleFactVariable, Path> fact2Path, final boolean isPositive) {
			// Collect the existential FactVariables and corresponding paths from the existentialCE
			final Map<SingleFactVariable, Path> existentialFact2Path =<commit_msg>patched the PathFilterConsolidator to create a further PathFilter combining all "unjoined" paths<commit_after>package org.jamocha.dn.compiler;

import static java.util.stream.Collectors.toCollection;
import static java.util.stream.Collectors.toSet;
import static org.jamocha.util.ToArray.toArray;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

import org.jamocha.dn.ConstructCache.Defrule;
import org.jamocha.dn.ConstructCache.Defrule.TranslatedPath;
import org.jamocha.filter.Path;
import org.jamocha.filter.PathCollector;
import org.jamocha.filter.PathFilter;
import org.jamocha.filter.PathFilter.PathFilterElement;
import org.jamocha.languages.common.ConditionalElement;
import org.jamocha.languages.common.ConditionalElement.AndFunctionConditionalElement;
import org.jamocha.languages.common.ConditionalElement.ExistentialConditionalElement;
import org.jamocha.languages.common.ConditionalElement.InitialFactConditionalElement;
import org.jamocha.languages.common.ConditionalElement.NegatedExistentialConditionalElement;
import org.jamocha.languages.common.ConditionalElement.NotFunctionConditionalElement;
import org.jamocha.languages.common.ConditionalElement.OrFunctionConditionalElement;
import org.jamocha.languages.common.ConditionalElement.SharedConditionalElementWrapper;
import org.jamocha.languages.common.ConditionalElement.TestConditionalElement;
import org.jamocha.languages.common.DefaultConditionalElementsVisitor;
import org.jamocha.languages.common.SingleFactVariable;

/**
 * Collect all PathFilters inside all children of an OrFunctionConditionalElement, returning a List
 * of Lists. Each inner List contains the PathFilters of one child.
 * 
 * @author <NAME> <<EMAIL>>
 * @author <NAME> <<EMAIL>>
 */
@RequiredArgsConstructor
public class PathFilterConsolidator implements DefaultConditionalElementsVisitor {

	private final Defrule rule;
	@Getter
	private List<Defrule.TranslatedPath> translateds = null;

	public List<Defrule.TranslatedPath> consolidate() {
		assert rule.getCondition().getConditionalElements().size() == 1;
		return rule.getCondition().getConditionalElements().get(0).accept(this).translateds;
	}

	@Override
	public void defaultAction(final ConditionalElement ce) {
		// If we are to need the initial fact variable, there should be one within the CE
		final SingleFactVariable initialFactVariable = SomeInitialFactFinder.find(ce);
		// If there is no OrFunctionConditionalElement just proceed with the CE as it were
		// the only child of an OrFunctionConditionalElement.
		translateds =
				Collections.singletonList(NoORsPFC.consolidate(rule, initialFactVariable, ce));
	}

	@Override
	public void visit(final OrFunctionConditionalElement ce) {
		// If we are to need the initial fact variable, there should be one within the CE
		final SingleFactVariable initialFactVariable = SomeInitialFactFinder.find(ce);
		// For each child of the OrCE ...
		this.translateds =
				ce.getChildren().stream().map(child ->
				// ... collect all PathFilters in the child
						NoORsPFC.consolidate(rule, initialFactVariable, child))
						.collect(Collectors.toCollection(ArrayList::new));

	}

	/**
	 * @author <NAME> <<EMAIL>>
	 * @author <NAME> <<EMAIL>>
	 */
	@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
	static class NoORsPFC implements DefaultConditionalElementsVisitor {

		private final SingleFactVariable initialFactVariable;
		private final Map<SingleFactVariable, Path> paths;
		private final boolean negated;

		@Getter
		private List<PathFilter> pathFilters = new ArrayList<>();

		private NoORsPFC(final SingleFactVariable initialFactVariable,
				final Map<SingleFactVariable, Path> paths) {
			this(initialFactVariable, paths, false);
		}

		public static TranslatedPath consolidate(final Defrule rule,
				final SingleFactVariable initialFactVariable, final ConditionalElement ce) {
			final Map<SingleFactVariable, Path> pathMap = FactVariableCollector.collectPaths(ce);
			final NoORsPFC instance = new NoORsPFC(initialFactVariable, pathMap).collect(ce);
			final List<PathFilter> pathFilters = instance.getPathFilters();

			final Set<Path> allPaths = new HashSet<>(pathMap.values());
			final Set<Path> collectedPaths =
					(pathFilters.isEmpty() ? Collections.<Path> emptySet() : PathCollector
							.newHashSet().collect(pathFilters.get(pathFilters.size() - 1))
							.getPaths().stream().flatMap((p) -> p.getJoinedWith().stream())
							.collect(toSet()));

			final TranslatedPath translated = rule.newTranslated(pathFilters, pathMap);
			if (collectedPaths.containsAll(allPaths)) {
				return translated;
			}
			pathFilters.add(new PathFilter(new PathFilter.DummyPathFilterElement(toArray(
					collectedPaths.isEmpty() ? allPaths : collectedPaths, Path[]::new))));
			return translated;
		}

		private <T extends ConditionalElement> NoORsPFC collect(final T ce) {
			return ce.accept(this);
		}

		static List<PathFilter> processExistentialCondition(
				final SingleFactVariable initialFactVariable, final ConditionalElement ce,
				final Map<SingleFactVariable, Path> fact2Path, final boolean isPositive) {
			// Collect the existential FactVariables and corresponding paths from the existentialCE
			final Map<SingleFactVariable, Path> existentialFact2Path =
{'fraction_non_alphanumeric': 0.09054436035378864, 'fraction_numerical': 0.0008206437494301085, 'mean_word_length': 5.770370370370371, 'pattern_counts': {'":': 0, '<': 59, '<?xml version=': 0, '>': 62, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '412973', 'n_tokens_mistral': 3366, 'n_tokens_neox': 3051, 'n_words': 734}