private ParseDelta enter() { return ParseDelta // Start the left. .builder(first) // Push this so that we can remember to do b if a passes. .push() .build(); }
private ParseDelta exitPass() { // Continue to the next entry. return ParseDelta.builder(second).build(); }
/** * Executes A and then B on the remaining input. * * <p>This matches the minimal language {∀a∈A,%forall;b%isin;concatenation(a, b)}. */ public final class SeqCombinator extends BinaryCombinator { /** */ public SeqCombinator(Supplier<NodeMetadata> mds, Combinator first, Combinator second) { super(mds, first, second); } @Override protected SeqCombinator unfold( NodeMetadata newMetadata, Function<ProdName, ProdName> renamer, Combinator newFirst, Combinator newSecond) { if (newMetadata.equals(this.md) && this.first == newFirst && this.second == newSecond) { return this; } return new SeqCombinator(Suppliers.ofInstance(newMetadata), newFirst, newSecond); } @Override public ParseDelta enter(Parse p) { return enter(); } @Override public ParseDelta exit(Parse p, Success s) { switch (s) { case FAIL: return EXIT_FAIL; case PASS: return exitPass(); } throw new AssertionError(s); } @Override public final ImmutableList<ParseDelta> epsilonTransition( TransitionType tt, Language lang, OutputContext ctx) { switch (tt) { case ENTER: return ImmutableList.of(enter()); case EXIT_PASS: return ImmutableList.of(exitPass()); case EXIT_FAIL: return ImmutableList.of(EXIT_FAIL); } throw new AssertionError(tt); } private ParseDelta enter() { return ParseDelta // Start the left. .builder(first) // Push this so that we can remember to do b if a passes. .push() .build(); } private static final ParseDelta EXIT_FAIL = ParseDelta.fail().build(); private ParseDelta exitPass() { // Continue to the next entry. return ParseDelta.builder(second).build(); } @Override public Precedence precedence() { return Precedence.SEQUENCE; } @Override protected String getVizTypeClassName() { return "seq"; } @Override protected void visualizeBody(DetailLevel lvl, VizOutput out) throws IOException { writeBinaryOperator( first, second, precedence(), Predicates.instanceOf(SeqCombinator.class), STRING_COALESCING_INFIXER, lvl, out); } @Override public Frequency consumesInput(Language lang) { Frequency ff = lang.lali.consumesInput(first); switch (ff) { case NEVER: return lang.lali.consumesInput(second); case ALWAYS: return ff; case SOMETIMES: Frequency sf = lang.lali.consumesInput(second); switch (sf) { case ALWAYS: case SOMETIMES: return sf; case NEVER: return Frequency.SOMETIMES; } throw new AssertionError(sf.name()); } throw new AssertionError(ff.name()); } @Override public ImmutableRangeSet<Integer> lookahead(Language lang) { Frequency ff = lang.lali.consumesInput(first); switch (ff) { case NEVER: return lang.lali.lookahead(second); case ALWAYS: return lang.lali.lookahead(first); case SOMETIMES: TreeRangeSet<Integer> r = TreeRangeSet.create(); r.addAll(lang.lali.lookahead(first)); r.addAll(lang.lali.lookahead(second)); return ImmutableRangeSet.copyOf(r); } throw new AssertionError(ff.name()); } @Override public boolean reachesWithoutConsuming(Combinator target, Language lang) { // Check whether target is reachable from any member. return super.reachesWithoutConsuming(target, lang) || first.reachesWithoutConsuming(target, lang) || (lang.lali.consumesInput(first) != Frequency.ALWAYS && second.reachesWithoutConsuming(target, lang)); } /** Finds sequences of characters that */ private static final Infixer STRING_COALESCING_INFIXER = new StringCoalescingInfixer(); }