package org.simantics.scl.compiler.parser.regexp; import gnu.trove.set.hash.THashSet; import java.util.Arrays; import java.util.Iterator; import org.simantics.scl.compiler.parser.regexp.automata.NFA; public class ROr extends Regexp { public final Regexp[] exps; ROr(Regexp[] exps) { this.exps = exps; } @Override protected void buildAutomaton(NFA aut, int inState, int outState) { for(Regexp exp : exps) exp.buildAutomaton(aut, inState, outState); } @Override protected void toString(StringBuilder b, int prec) { if(prec >= 1) b.append('('); boolean first = true; for(Regexp exp : exps) { if(first) first = false; else b.append(" | "); exp.toString(b, 1); } if(prec >= 1) b.append(')'); } @Override public void toString(StringBuilder b, Namer grammar, int prec) { if(prec >= 1) b.append('('); boolean first = true; for(Regexp exp : exps) { if(first) first = false; else b.append(" | "); exp.toString(b, grammar, 1); } if(prec >= 1) b.append(')'); } @Override protected int getTypeId() { return OR; } @Override public boolean equals(Object obj) { if(obj == this) return true; if(obj == null || obj.getClass() != getClass()) return false; ROr other = (ROr)obj; return Arrays.equals(exps, other.exps); } @Override public int hashCode() { int r = 34235; for(Regexp exp : exps) { r *= 31; r += exp.hashCode(); } return r; } @Override public boolean isNullable() { for(Regexp exp : exps) if(exp.isNullable()) return true; return false; } private Regexp simplify(THashSet set) { boolean qm = set.remove(ONE); Regexp exp; simpl: { if(set.size() > 1) { frontLoop: { Iterator it = set.iterator(); Regexp common = front(it.next()); while(it.hasNext()) { Regexp temp = front(it.next()); if(!temp.equals(common)) break frontLoop; } THashSet set2 = new THashSet(); for(Regexp e : set) set2.add(removeFront(e)); exp = seq(common, simplify(set2)); break simpl; } backLoop: { Iterator it = set.iterator(); Regexp common = back(it.next()); while(it.hasNext()) { Regexp temp = back(it.next()); if(!temp.equals(common)) break backLoop; } THashSet set2 = new THashSet(); for(Regexp e : set) set2.add(removeBack(e)); exp = seq(simplify(set2), common); break simpl; } } exp = or(set); } if(qm && !exp.isNullable()) exp = new ROp(exp, '?'); return exp; } @Override public Regexp simplify() { if(exps.length == 0) return this; THashSet set = new THashSet(); for(Regexp exp : exps) { exp = exp.simplify(); or(set, exp); } return simplify(set); } private static Regexp front(Regexp exp) { if(exp instanceof RSeq) { Regexp[] exps = ((RSeq)exp).exps; if(exps.length == 0) return null; return exps[0]; } else return exp; } private static Regexp removeFront(Regexp exp) { if(exp instanceof RSeq) { Regexp[] exps = ((RSeq)exp).exps; return seq_(Arrays.asList(exps).subList(1, exps.length)); } else return ONE; } private static Regexp back(Regexp exp) { if(exp instanceof RSeq) { Regexp[] exps = ((RSeq)exp).exps; if(exps.length == 0) return null; return exps[exps.length-1]; } else return exp; } private static Regexp removeBack(Regexp exp) { if(exp instanceof RSeq) { Regexp[] exps = ((RSeq)exp).exps; return seq_(Arrays.asList(exps).subList(0, exps.length-1)); } else return ONE; } }