package com.googlecode.totallylazy.parser;
import com.googlecode.totallylazy.Functor;
import com.googlecode.totallylazy.Segment;
import com.googlecode.totallylazy.functions.Binary;
import com.googlecode.totallylazy.functions.Callables;
import com.googlecode.totallylazy.functions.Function1;
import com.googlecode.totallylazy.Option;
import com.googlecode.totallylazy.Pair;
import com.googlecode.totallylazy.Sequence;
import com.googlecode.totallylazy.Sequences;
import com.googlecode.totallylazy.functions.Unary;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.List;
import static com.googlecode.totallylazy.Segment.constructors.characters;
import static com.googlecode.totallylazy.Sequences.foldLeft;
import static com.googlecode.totallylazy.Sequences.foldRight;
import static com.googlecode.totallylazy.Sequences.join;
import static com.googlecode.totallylazy.Strings.UTF8;
public interface Parser<A> extends Functor<A> {
Result<A> parse(Segment<Character> characters);
default Failure<A> fail(Object expected, Object actual) {
return Failure.failure(expected, actual);
}
@Override String toString();
@Override
default <B> Parser<B> map(Function1<? super A, ? extends B> callable) {
return MappingParser.map(this, callable);
}
default <B> Parser<B> flatMap(Function1<? super A, ? extends Result<B>> callable) {
return FlatMappingParser.flatMap(this, callable);
}
default <B> Parser<Pair<A, B>> then(Parser<? extends B> parser) {
return PairParser.pair(this, parser);
}
default <B> Parser<B> next(Parser<? extends B> parser) {
return then(parser).map(Callables.<B>second());
}
default Parser<A> followedBy(Parser<?> parser) {
return then(parser).map(Callables.<A>first());
}
default Parser<A> between(Parser<?> before, Parser<?> after) {
return Parsers.between(before, this, after);
}
default Parser<A> surroundedBy(Parser<?> parser) {
return between(parser, parser);
}
default Parser<List<A>> sepBy(Parser<?> parser) {
return separatedBy(parser);
}
default Parser<List<A>> sepBy1(Parser<?> parser) {
return followedByOption(parser).many(1);
}
default Parser<List<A>> separatedBy(Parser<?> parser) {
return followedByOption(parser).many();
}
default Parser<A> followedByOption(Parser<?> parser) {return followedBy(OptionalParser.optional(parser));}
default Parser<Sequence<A>> seqBy(Parser<?> parser) {
return sequencedBy(parser);
}
default Parser<Sequence<A>> sequencedBy(Parser<?> parser) {
return followedByOption(parser).sequence();
}
default Parser<A> or(Parser<? extends A> parser) {
return Parsers.or(this, parser);
}
default Parser<Option<A>> optional() {
return OptionalParser.optional(this);
}
default Result<A> parse(CharSequence value) {
return parse(characters(value));
}
default Result<A> parse(Reader value) {
return parse(characters(value));
}
default Result<A> parse(InputStream value) {
return parse(characters(new InputStreamReader(value, UTF8)));
}
default Parser<Void> ignore() {
return map(value -> null);
}
default Parser<List<A>> times(int number) {
return Parsers.list(Sequences.repeat(this).take(number));
}
default Parser<List<A>> many() {
return ManyParser.many(this);
}
default Parser<Sequence<A>> sequence() {
return SequenceParser.sequence(this);
}
default Parser<A> pretty(String pretty) {
return Parsers.pretty(pretty, this);
}
default Parser<List<A>> many1() {
return many(1);
}
default Parser<List<A>> many(int min) {
return times(min).then(many()).map(p -> join(p.first(), p.second()).toList());
}
default Parser<A> debug(String name) {
return Parsers.debug(name, this);
}
default <R> Parser<R> returns(R value) {
return next(Parsers.returns(value));
}
default Parser<A> peek() {
return new PeekParser<>(this);
}
default Parser<A> peek(Parser<A> parser) {
return followedBy(parser.peek());
}
default Parser<A> infixLeft(Parser<? extends Binary<A>> op){
return then(op.then(this).many()).map(pair ->
foldLeft(pair.second(), pair.first(), (a, p) -> p.first().call(a, p.second())));
}
default Parser<A> infixRight(Parser<? extends Binary<A>> op){
return then(op).many().then(this).map(pair ->
foldRight(pair.first(), pair.second(), (p, a) -> p.second().call(p.first(), a)));
}
default Parser<A> prefix(Parser<? extends Unary<A>> op){
return op.many().then(this).map(pair ->
foldLeft(pair.first(), pair.second(), (a, p) -> p.call(a) ));
}
}