RegexComposer.java

package com.github.dakusui.jcunitx.metamodel.parameters.regex;

import com.github.dakusui.jcunitx.core.AArray;
import com.github.dakusui.jcunitx.pipeline.stages.Generator;
import com.github.dakusui.jcunitx.regex.Expr;
import com.github.dakusui.jcunitx.regex.Reference;
import com.github.dakusui.jcunitx.regex.RegexTranslator;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import static java.util.Arrays.asList;

public class RegexComposer {
  private final String            prefix;
  private final Expr              topLevel;
  private final Map<String, Expr> exprs;

  public RegexComposer(String prefix, Expr topLevel) {
    this.prefix = prefix;
    this.topLevel = topLevel;
    this.exprs = createMap(this.topLevel);
  }

  /**
   * A method to compose a sequence of `String`s that matches the expression given as `topLevel` from `row`.
   *
   * @param row An internal representation of a sequence matching the `topLevel` expression (`Expr`).
   * @return A sequence matching requested `Expr`.
   */
  public List<String> compose(AArray row) {
    ComposerVisitor visitor = new ComposerVisitor(row, this.exprs);
    this.topLevel.accept(visitor);
    return splitOnWhiteSpaces(visitor.out);
  }

  private List<String> splitOnWhiteSpaces(List<Object> in) {
    List<String> ret = new LinkedList<>();
    for (Object each : in) {
      String eachString = (String) each;
      if (!eachString.contains(" ")) {
        ret.add(eachString);
      } else {
        ret.addAll(asList(eachString.split(" +")));
      }
    }
    return ret;
  }

  private Map<String, Expr> createMap(Expr top) {
    final Map<String, Expr> ret = new HashMap<>();
    top.accept(new Expr.Visitor() {
      @Override
      public void visit(Expr.Alt exp) {
        ret.put(RegexComposer.this.composeKey(exp), exp);
        for (Expr each : exp.getChildren()) {
          each.accept(this);
        }
      }

      @Override
      public void visit(Expr.Cat exp) {
        ret.put(RegexComposer.this.composeKey(exp), exp);
        for (Expr each : exp.getChildren()) {
          each.accept(this);
        }
      }

      @Override
      public void visit(Expr.Leaf exp) {
        ret.put(RegexComposer.this.composeKey(exp), exp);
      }

      @Override
      public void visit(Expr.Empty exp) {
        ret.put(RegexComposer.this.composeKey(exp), exp);
      }
    });
    return ret;
  }

  private String composeKey(Expr expr) {
    return RegexTranslator.composeKey(this.prefix, expr.id());
  }

  private class ComposerVisitor implements Expr.Visitor {
    private final AArray            tuple;
    private final Map<String, Expr> exprs;
    public        List<Object>      out = new LinkedList<>();

    private ComposerVisitor(AArray tuple, Map<String, Expr> exprs) {
      this.tuple = tuple;
      this.exprs = exprs;
    }

    @Override
    public void visit(Expr.Alt expr) {
      Object values = tuple.get(composeKey(expr));
      if (Generator.VOID.equals(values))
        return;
      //noinspection unchecked
      for (Object each : (List<Object>) values) {
        if (each instanceof Reference) {
          this.exprs.get(((Reference) each).key).accept(this);
        } else {
          out.add(each);
        }
      }
    }

    @Override
    public void visit(Expr.Cat expr) {
      for (Expr each : expr.getChildren()) {
        each.accept(this);
      }
    }

    @Override
    public void visit(Expr.Leaf expr) {
      out.add(expr.value());
    }

    @Override
    public void visit(Expr.Empty empty) {

    }
  }
}