/** 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); }
/** * A {@link Parser} that runs {@code this} for 0 ore more times separated and optionally terminated by {@code * delim}. For example: {@code "foo;foo;foo"} and {@code "foo;foo;"} both matches {@code foo.sepEndBy(semicolon)}. * * <p>The return values are collected in a {@link List}. */ public final Parser<List<T>> sepEndBy(Parser<?> delim) { return Parsers.or(sepEndBy1(delim), EmptyListParser.<T>instance()); }
/** * A {@link Parser} that greedily runs {@code tokenizer}, and translates line feed characters * ({@code '\n'}) to {@code indent} and {@code outdent} tokens. * Return values are wrapped in {@link Token} objects and collected in a {@link List}. * Patterns recognized by {@code delim} are ignored. */ public Parser<List<Token>> lexer(Parser<?> tokenizer, Parser<?> delim) { Parser<?> lf = Scanners.isChar('\n').retn(Punctuation.LF); return Parsers.or(tokenizer, lf).lexer(delim) .map(tokens -> analyzeIndentations(tokens, Punctuation.LF)); }
@Override boolean apply(ParseContext ctxt) { int from = ctxt.at; if (!outer.apply(ctxt)) return false; ScannerState innerState = new ScannerState( ctxt.module, ctxt.characters(), from, ctxt.at, ctxt.locator, ctxt.result); ctxt.getTrace().startFresh(innerState); innerState.getTrace().setStateAs(ctxt.getTrace()); return ctxt.applyNested(inner, innerState); } @Override public String toString() {
@Override boolean apply(ParseContext ctxt) { if (!lexer.apply(ctxt)) return false; Token[] tokens = lexer.getReturn(ctxt); ParserState parserState = new ParserState( ctxt.module, ctxt.source, tokens, 0, ctxt.locator, ctxt.getIndex(), tokens); ctxt.getTrace().startFresh(parserState); return ctxt.applyNested(parser, parserState); }
/** * A {@link Parser} that runs {@code this} 1 or more times separated by {@code delim}. * * <p>The return values are collected in a {@link List}. */ public final Parser<List<T>> sepBy1(Parser<?> delim) { final Parser<T> afterFirst = delim.asDelimiter().next(this); return next((Function<T, Parser<List<T>>>) firstValue -> new RepeatAtLeastParser<T>( afterFirst, 0, ListFactory.arrayListFactoryWithFirstElement(firstValue))); }
/** * A {@link Parser} that fails if {@code this} succeeds. Any input consumption is undone. * * @param unexpected the name of what we don't expect. */ public final Parser<?> not(String unexpected) { return peek().ifelse(Parsers.unexpected(unexpected), Parsers.always()); }
/** * 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 {@code this} for 1 ore more times separated and optionally terminated by {@code * delim}. For example: {@code "foo;foo;foo"} and {@code "foo;foo;"} both matches {@code foo.sepEndBy1(semicolon)}. * * <p>The return values are collected in a {@link List}. */ public final Parser<List<T>> sepEndBy1(final Parser<?> delim) { return next(first -> new DelimitedParser<T>(this, delim, ListFactory.arrayListFactoryWithFirstElement(first))); }
final ParseTree buildParseTree() { TreeNode currentNode = trace.getCurrentNode(); if (currentNode == null) return null; return currentNode.freeze(getIndex()).toParseTree(); }
/** * A {@link Parser} that runs {@code op} for 0 or more times greedily, then runs {@code this}. * The {@link Function} objects returned from {@code op} are applied from right to left to the * return value of {@code p}. * * <p> {@code p.prefix(op)} is equivalent to {@code op* p} in EBNF. */ public final Parser<T> prefix(Parser<? extends Function<? super T, ? extends T>> op) { return Parsers.sequence(op.many(), this, Parser::applyPrefixOperators); }
/** * A {@link Parser} that takes as input the {@link Token} collection returned by {@code lexer}, * and runs {@code this} to parse the tokens. Most parsers should use the simpler * {@link #from(Parser, Parser)} instead. * * <p> {@code this} must be a token level parser. */ public final Parser<T> from(Parser<? extends Collection<Token>> lexer) { return Parsers.nested(Parsers.tokens(lexer), followedBy(Parsers.EOF)); }
@Override boolean apply(ParseContext ctxt) { List<T> result = listFactory.newList(); if (!ctxt.repeat(parser, min, result)) return false; if (repeatAtMost(max - min, result, ctxt)) { ctxt.result = result; return true; } return false; }
/** * Returns a {@link Parser} that recognizes {@link Tokens.Fragment} token values * tagged with one of {@code tags}. */ public static Parser<String> fragment(final Object... tags) { return Parsers.token(fromFragment(tags)); }
/** * 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); }