/** * A {@link Parser} that tries each alternative parser in {@code alternatives}. * * <p> Different than {@link #alt(Parser[])}, it requires all alternative parsers to have * type {@code T}. */ public static <T> Parser<T> or(final Parser<? extends T>... alternatives) { if (alternatives.length == 0) return never(); if (alternatives.length == 1) return alternatives[0].cast(); return new Parser<T>() { @Override boolean apply(ParseContext ctxt) { final Object result = ctxt.result; final int at = ctxt.at; final int step = ctxt.step; for(Parser<? extends T> p : alternatives) { if (p.apply(ctxt)) { return true; } ctxt.set(step, at, result); } return false; } @Override public String toString() { return "or"; } }; }
/** * A {@link Parser} that runs every element of {@code parsers} and selects the longest match. * If two matches have the same length, the first one is favored. */ public static <T> Parser<T> longest(Parser<? extends T>... parsers) { if (parsers.length == 0) return never(); if (parsers.length == 1) return parsers[0].cast(); return new BestParser<T>(parsers, IntOrder.GT); }
/** * A {@link Parser} that runs every element of {@code parsers} and selects the shortest match. * If two matches have the same length, the first one is favored. */ public static <T> Parser<T> shortest(Parser<? extends T>... parsers) { if (parsers.length == 0) return never(); if (parsers.length == 1) return parsers[0].cast(); return new BestParser<T>(parsers, IntOrder.LT); }
/** A {@link Parser} that recognizes a token identified by any of {@code tokenNames}. */ public Parser<Token> token(String... tokenNames) { if (tokenNames.length == 0) return Parsers.never(); @SuppressWarnings("unchecked") Parser<Token>[] ps = new Parser[tokenNames.length]; for(int i = 0; i < tokenNames.length; i++) { ps[i] = Parsers.token(InternalFunctors.tokenWithSameValue(word(tokenNames[i]))); } return Parsers.or(ps); }