--- /dev/null
+package org.simantics.scl.compiler.parser.regexp;
+
+import org.simantics.scl.compiler.parser.regexp.automata.NFA;
+
+public class ROp extends Regexp {
+ public final Regexp exp;
+ public final char op;
+
+ ROp(Regexp exp, char op) {
+ this.exp = exp;
+ this.op = op;
+ }
+
+ @Override
+ public Regexp simplify() {
+ Regexp exp = this.exp.simplify();
+ if(exp instanceof ROp) {
+ ROp other = (ROp)exp;
+ if(other.op == op || other.op == '*')
+ return other;
+ else
+ return new ROp(other.exp, '*');
+ }
+ else if(exp.isNullable()) {
+ if(op == '?')
+ return exp;
+ if(op == '+')
+ return new ROp(exp, '*');
+ }
+ if(exp == this.exp)
+ return this;
+ else
+ return new ROp(exp, op);
+ }
+
+ @Override
+ protected void buildAutomaton(NFA aut, int inState, int outState) {
+ switch(op) {
+ case '?':
+ exp.buildAutomaton(aut, inState, outState);
+ aut.addEpsilonTransition(inState, outState);
+ break;
+ case '*': {
+ int state = aut.newState();
+ aut.addEpsilonTransition(inState, state);
+ exp.buildAutomaton(aut, state, state);
+ aut.addEpsilonTransition(state, outState);
+ } break;
+ case '+': {
+ int state1 = aut.newState();
+ int state2 = aut.newState();
+ aut.addEpsilonTransition(inState, state1);
+ exp.buildAutomaton(aut, state1, state2);
+ aut.addEpsilonTransition(state2, state1);
+ aut.addEpsilonTransition(state2, outState);
+ } break;
+ default:
+ throw new IllegalStateException("Invalid operation '" + op + "'.");
+ }
+ }
+
+ @Override
+ protected void toString(StringBuilder b, int prec) {
+ exp.toString(b, 3);
+ b.append(op);
+ }
+
+ @Override
+ public void toString(StringBuilder b, Namer grammar, int prec) {
+ exp.toString(b, grammar, 3);
+ b.append(op);
+ }
+
+ @Override
+ protected int getTypeId() {
+ return OP;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if(obj == this)
+ return true;
+ if(obj == null || obj.getClass() != getClass())
+ return false;
+ ROp other = (ROp)obj;
+ return op == other.op && exp.equals(other.exp);
+ }
+
+ @Override
+ public int hashCode() {
+ return 31*exp.hashCode() + op;
+ }
+
+ @Override
+ public boolean isNullable() {
+ return op != '+' || exp.isNullable();
+ }
+}