Expr.java
package com.github.dakusui.jcunitx.regex;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import static java.lang.String.format;
import static java.util.stream.Collectors.toList;
public interface Expr {
void accept(Visitor visitor);
String id();
enum Utils {
;
static String str(Object value) {
return value == null ?
null :
value.toString();
}
}
abstract class Base implements Expr {
private final String id;
Base(AtomicInteger counter) {
this.id = composeId(counter);
}
String composeId(AtomicInteger counter) {
return format("%s-%d", composeName(), counter.getAndIncrement());
}
String composeName() {
return this.getClass().getSimpleName().toLowerCase();
}
public String id() {
return id;
}
}
class Empty extends Base implements Expr {
static Empty INSTANCE = new Empty(new AtomicInteger(0));
Empty(AtomicInteger counter) {
super(counter);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String toString() {
return "";
}
}
class Leaf extends Base implements Expr {
private final Object value;
Leaf(AtomicInteger counter, Object value) {
super(counter);
this.value = value;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
public Object value() {
return this.value;
}
@Override
public String toString() {
return Utils.str(this.value());
}
}
/**
* Concatenation of elements.
*/
class Cat extends Composite implements Expr {
Cat(AtomicInteger counter, List<Expr> children) {
super(counter, children);
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
/**
* Alternative of elements.
*/
class Alt extends Composite implements Expr {
Alt(AtomicInteger counter, List<Expr> children) {
super(counter, children);
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
/**
* Repetition of elements
*/
class Rep extends Alt {
private static final Expr EMPTY = Empty.INSTANCE;
private final int min;
private final int max;
Rep(AtomicInteger counter, Expr child, int min, int max) {
super(counter, createChildren(counter, child, min, max));
this.min = min;
this.max = max;
}
public String name() {
return format("%s{%s,%s}", super.name(), this.min, this.max);
}
@Override
public String toString() {
return name();
}
private static List<Expr> createChildren(AtomicInteger counter, Expr child, int min, int max) {
List<Expr> ret = new LinkedList<>();
for (int i = min; i <= max; i++) {
if (i == 0) {
ret.add(EMPTY);
} else {
List<Expr> work = new LinkedList<>();
for (int j = 0; j < min; j++) {
work.add(child);
}
for (int j = min; j < i; j++) {
work.add(cloneIfAlt(counter, child));
}
ret.add(
work.size() == 1 ?
work.get(0) :
new Cat(counter, work)
);
}
}
return ret;
}
private static Expr cloneIfAlt(final AtomicInteger counter, Expr cur) {
if (cur instanceof Alt) {
return new Alt(counter, ((Alt) cur).getChildren().stream().map(in -> cloneIfAlt(counter, in)).collect(toList()));
}
return cur;
}
}
abstract class Composite extends Base implements Expr {
private final List<Expr> children;
Composite(AtomicInteger counter, List<Expr> children) {
super(counter);
this.children = children;
}
public List<Expr> getChildren() {
return this.children;
}
public String toString() {
return format("%s:%s", name(), this.getChildren());
}
public String name() {
return this.getClass().getSimpleName().toLowerCase();
}
}
interface Visitor {
void visit(Alt exp);
void visit(Cat exp);
void visit(Leaf leaf);
void visit(Empty empty);
}
class Factory {
private final AtomicInteger counter;
public Factory() {
this.counter = new AtomicInteger(1);
}
Expr leaf(Object value) {
return new Leaf(counter, value);
}
Expr cat(List<Expr> exps) {
return new Cat(this.counter, exps.stream().map(in -> {
if (in != null) {
return in;
}
return new Leaf(counter, in);
}).collect(toList()));
}
Expr alt(List<Expr> exps) {
return new Alt(counter, exps.stream().map(in -> {
if (in != null) {
return in;
}
return new Leaf(counter, in);
}).collect(toList()));
}
Expr rep(Object exp, int min, int max) {
return new Rep(counter, exp instanceof Expr ? (Expr) exp : new Leaf(counter, exp), min, max);
}
}
}