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

org.pitest.sequence.SequenceQuery Maven / Gradle / Ivy

There is a newer version: 1.17.1
Show newest version
package org.pitest.sequence;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class SequenceQuery {

  private final Partial token;

  SequenceQuery(Partial token) {
    this.token = token;
  }

  public SequenceQuery then(Match next) {
    return then(new SequenceQuery<>(new Literal<>(next)));
  }

  public SequenceQuery then(SequenceQuery next) {
    final Concat concat = new Concat<>(this.token, next.token);
    return new SequenceQuery<>(concat);
  }

  public SequenceQuery or(SequenceQuery next) {
    final Or or = new Or<>(this.token, next.token);
    return new SequenceQuery<>(or);
  }

  public SequenceQuery thenAnyOf(SequenceQuery left,
      SequenceQuery right) {
    final Or or = new Or<>(left.token, right.token);
    final Concat concat = new Concat<>(this.token, or);
    return new SequenceQuery<>(concat);
  }

  public SequenceQuery zeroOrMore(SequenceQuery next) {
    final Concat concat = new Concat<>(this.token, new Repeat<>(next.token));
    return new SequenceQuery<>(concat);
  }

  public SequenceQuery oneOrMore(SequenceQuery next) {
    final Concat concat = new Concat<>(this.token, new Plus<>(next.token));
    return new SequenceQuery<>(concat);
  }

  public SequenceMatcher compile() {
    return compile(QueryParams.params());
  }

  @SuppressWarnings("unchecked")
  public SequenceMatcher compile(QueryParams params) {
    return new NFASequenceMatcher(params.ignoring(),
        this.token.make(EndMatch.MATCH), params.isDebug());
  }

  interface Partial {
    State make(State andThen);
  }

  static class Literal implements Partial {
    final Match< T> c;

    Literal(Match<  T> p) {
      this.c = p;
    }

    @Override
    public State make(State andThen) {
      return new Consume<>(this.c, andThen);
    }
  }

  static class Or implements Partial {
    final Partial left;
    final Partial right;

    Or(Partial left, Partial right) {
      this.left = left;
      this.right = right;
    }

    @Override
    public State make(State andThen) {
      final State l = this.left.make(andThen);
      final State r = this.right.make(andThen);
      return new Split<>(l, r);
    }

  }

  static class Concat implements Partial {
    final Partial left;
    final Partial right;

    Concat(Partial left, Partial right) {
      this.left = left;
      this.right = right;
    }

    @Override
    public State make(State andThen) {
      return this.left.make(this.right.make(andThen));
    }
  }

  static class Repeat implements Partial {
    final Partial r;

    Repeat(Partial r) {
      this.r = r;
    }

    @Override
    public State make(State andThen) {
      final Split placeHolder = new Split<>(null, null);
      final State right = this.r.make(placeHolder);
      placeHolder.out1 = new Split<>(right, andThen);
      return placeHolder;
    }

  }

  static class Plus implements Partial {
    final Partial r;

    Plus(Partial r) {
      this.r = r;
    }

    @Override
    public State make(State andThen) {
      final Concat concat = new Concat<>(this.r, new Repeat<>(this.r));
      return concat.make(andThen);
    }
  }

}

class NFASequenceMatcher implements SequenceMatcher {

  private final boolean debug;
  private final Match ignore;
  private final State start;

  NFASequenceMatcher(Match ignore, State state, boolean debug) {
    this.ignore = ignore;
    this.start = state;
    this.debug = debug;
  }


  @Override
  public boolean matches(List sequence) {
    return matches(sequence, Context.start(this.debug));
  }

  @Override
  public boolean matches(List sequence, Context initialContext) {
    Set> currentState = run(sequence, initialContext);
    return currentState.stream()
            .map(c -> c.state)
            .anyMatch(s -> s != null && s == EndMatch.MATCH);
  }

  @Override
  public List contextMatches(List sequence, Context initialContext) {
    Set> currentState = run(sequence, initialContext);
    return currentState.stream()
            .filter(s -> s.state != null && s.state == EndMatch.MATCH)
            .map(c -> c.context)
            .collect(Collectors.toList());
  }

  private Set> run(List sequence, Context initialContext) {
    Set> currentState = new HashSet<>();
    addState(currentState, new StateContext<>(this.start, initialContext));

    for (final T t : sequence) {
      // only initial context used in ignore checks
      if (this.ignore.test(initialContext, t).result()) {
        continue;
      }

      final Set> nextStates = step(currentState, t);
      currentState = nextStates;

    }
    return currentState;
  }


  private static  void addState(Set> set, StateContext state) {

    if (state.state instanceof Split) {
      final Split split = (Split) state.state;
      if (split.out1 != null) {
        addState(set, new StateContext(split.out1, state.context));
      }
      if (split.out2 != null) {
        addState(set, new StateContext(split.out2, state.context));
      }
    } else {
      set.add(state);
    }

  }

  private static  Set> step(Set> currentState, T c) {

    // adhoc testing suggests setting the initial HashSet size saves 15% of analysis
    // execution time
    final Set> nextStates = new HashSet<>(currentState.size());

    for (final StateContext each : currentState) {
      if (each.state instanceof Consume) {
        final Consume consume = (Consume) each.state;

        final Result result = consume.c.test(each.context, c);
        if (result.result()) {
          // note, context updated here
          addState(nextStates, new StateContext<>(consume.out, result.context()));
        }
      }
    }
    return nextStates;
  }

}

interface State {

}

class Consume implements State {
  final Match c;
  final State out;

  Consume(Match c, State out) {
    this.c = c;
    this.out = out;
  }

}

class Split implements State {
  State out1;
  final State out2;

  Split(State out1, State out2) {
    this.out1 = out1;
    this.out2 = out2;
  }
}

@SuppressWarnings("rawtypes")
enum EndMatch implements State {
  MATCH
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy