All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.dakusui.jcunit8.factorspace.regex.RegexDecomposer Maven / Gradle / Ivy

The newest version!
package com.github.dakusui.jcunit8.factorspace.regex;

import com.github.dakusui.jcunit.core.tuples.Tuple;
import com.github.dakusui.jcunit.regex.Expr;
import com.github.dakusui.jcunit.regex.Reference;
import com.github.dakusui.jcunit.regex.RegexTranslator;
import com.github.dakusui.jcunit.regex.Value;
import com.github.dakusui.jcunit8.factorspace.Constraint;
import com.github.dakusui.jcunit8.factorspace.Factor;
import com.github.dakusui.jcunit8.factorspace.FactorSpace;
import com.github.dakusui.jcunit8.pipeline.stages.Generator;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

import static com.github.dakusui.jcunit.core.utils.Utils.concatenate;
import static java.util.Objects.requireNonNull;

public class RegexDecomposer extends RegexTranslator {

  public RegexDecomposer(String name, Expr topLevel) {
    super(topLevel, name);
  }

  public FactorSpace decompose() {
    List factors = buildFactors();
    return FactorSpace.create(factors, buildConstraints(factors));
  }

  private List buildFactors() {
    this.topLevelExpression.accept(this);
    final List builder = new LinkedList<>();
    for (String eachKey : this.terms.keySet()) {
      List b = new LinkedList<>();
      if (!isTopLevel(eachKey)) {
        if (isReferencedByAltDirectlyOrIndirectly(eachKey) || isAlt(eachKey)) {
          b.add(Generator.VOID);
        }
      }
      if (isAlt(eachKey)) {
        for (Value eachValue : this.terms.get(eachKey)) {
          b.add(resolveIfImmediate(eachValue));
        }
      } else /* , that is, if (isCat(eachKey)) */ {
        List work = new LinkedList<>();
        for (Value eachValue : this.terms.get(eachKey)) {
          work.addAll(this.resolve(eachValue));
        }
        b.add(work);
      }
      if (b.size() > 1 || (b.size() == 1 && isTopLevel(eachKey))) {
        builder.add(Factor.create(eachKey, b.toArray()));
      }
    }
    return Collections.unmodifiableList(builder);
  }

  private List buildConstraints(List factors) {
    List ret = new LinkedList<>();
    for (final Factor each : factors) {
      final List referrers = getReferringFactors(each, factors).stream()
          .map(Factor::getName)
          .collect(Collectors.toList());
      if (referrers.isEmpty())
        continue;
      final String referee = each.getName();
      final String tag = String.format("constraint(%s->%s)", referrers, referee);
      ret.add(new Constraint() {

        @Override
        public String getName() {
          return toString();
        }

        @Override
        public boolean test(Tuple in) {
          for (String eachReferrer : referrers) {
            Object referrerValue = in.get(eachReferrer);
            if (!Generator.VOID.equals(referrerValue) && isReferencedBy(referrerValue)) {
              return !Generator.VOID.equals(in.get(referee));
            }
          }
          return Generator.VOID.equals(in.get(referee));
        }

        @Override
        public List involvedKeys() {
          return concatenate(referrers, referee);
        }

        @Override
        public String toString() {
          return tag;
        }

        @SuppressWarnings("unchecked")
        boolean isReferencedBy(Object referrerValue) {
          return ((List) requireNonNull(referrerValue)).stream()
              .anyMatch(
                  (Object each) ->
                      each instanceof Reference &&
                          ((Reference) each).key.equals(referee)
              );
        }
      });
    }
    return ret;
  }

  private List getReferringFactors(Factor referred, List factors) {
    List ret = new LinkedList<>();
    outer:
    for (Factor each : factors) {
      if (each == referred)
        continue;
      for (Object eachLevel : each.getLevels()) {
        if (eachLevel instanceof List) {
          for (Object eachElement : (List) eachLevel) {
            if (eachElement instanceof Reference) {
              if (referred.getName().equals(((Reference) eachElement).key)) {
                ret.add(each);
                continue outer;
              }
            }
          }
        }
      }
    }
    return ret;
  }

}