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

de.scravy.bedrock.Parser Maven / Gradle / Ivy

The newest version!
package de.scravy.bedrock;

import lombok.*;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Optional;
import java.util.function.*;

@FunctionalInterface
public interface Parser {

  Result parse(final Seq seq);

  default  Parser map(final Function f) {
    return seq -> parse(seq).map(f);
  }

  @RequiredArgsConstructor(access = AccessLevel.PACKAGE)
  abstract class Result {

    public abstract  Result map(final Function f);

    public abstract Seq getRemaining();

    public abstract Result withRemaining(final Seq seq);

    public E getValue() {
      return null;
    }

    public boolean isSuccess() {
      return false;
    }

    public boolean isNoParse() {
      return false;
    }

    @SuppressWarnings("unchecked")
     Result as() {
      return (Result) this;
    }

    @Value
    @EqualsAndHashCode(callSuper = false)
    public static class Success extends Result {

      private final E value;

      @With
      private final Seq remaining;

      @Override
      public  Result map(final Function f) {
        return new Success<>(f.apply(value), remaining);
      }

      @Override
      public boolean isSuccess() {
        return true;
      }
    }

    @Value
    @EqualsAndHashCode(callSuper = false)
    public static class NoParse extends Result {

      @With
      private final Seq remaining;

      @SuppressWarnings("unchecked")
      @Override
      public  Result map(final Function f) {
        return (Result) this;
      }

      @Override
      public boolean isNoParse() {
        return true;
      }
    }
  }

  /**
   * Creates a parser that parses p1 and then p2 but returns the result of p1 (the left one).
   *
   * @param p1  The left parser.
   * @param p2  The right parser.
   * @param  The type parsed by the left parser.
   * @param  The type parsed by the right parser.
   * @return A parser that parses p1 and then p2 but returns the result of p1 (the left one).
   */
  static  Parser left(final Parser p1, final Parser p2) {
    return seq -> {
      final Result r1 = p1.parse(seq);
      if (r1.isSuccess()) {
        final Result r2 = p2.parse(r1.getRemaining());
        if (r2.isSuccess()) {
          return new Result.Success<>(r1.getValue(), r2.getRemaining());
        }
        return r2.withRemaining(seq).as();
      }
      return r1.withRemaining(seq);
    };
  }

  /**
   * Creates a parser that parses p1 and then p2 but returns the result of p2 (the right one).
   *
   * @param p1  The left parser.
   * @param p2  The right parser.
   * @param  The type parsed by the left parser.
   * @param  The type parsed by the right parser.
   * @return A parser that parses p1 and then p2 but returns the result of p2 (the right one).
   */
  static  Parser right(final Parser p1, final Parser p2) {
    return seq -> {
      final Result r1 = p1.parse(seq);
      if (r1.isSuccess()) {
        final Result r2 = p2.parse(r1.getRemaining());
        if (r2.isSuccess()) {
          return r2;
        }
        return r2.withRemaining(seq);
      }
      return r1.withRemaining(seq).as();
    };
  }

  static  Parser choice(final Parser p1, final Parser p2) {
    return seq -> {
      final Result r1 = p1.parse(seq);
      if (r1.isSuccess()) {
        return r1.as();
      }
      return p2.parse(seq).as();
    };
  }

  static  Parser> either(final Parser p1, final Parser p2) {
    return seq -> {
      final Result> r1 = p1.parse(seq).map(Either::left);
      if (r1.isSuccess()) {
        return r1;
      }
      return p2.parse(seq).map(Either::right);
    };
  }

  @SafeVarargs
  static  Parser oneOf(final Parser... ps) {
    return seq -> {
      for (final Parser p : ps) {
        final Result result = p.parse(seq);
        if (result.isSuccess()) {
          return result.as();
        }
      }
      return new Result.NoParse<>(seq);
    };
  }
  
  static  Parser satisfies(final Class clazz, final Predicate predicate) {
    return seq -> {
      if (seq.nonEmpty()) {
        final Object obj = seq.head();
        if (clazz.isAssignableFrom(obj.getClass())) {
          @SuppressWarnings("unchecked") final T t = (T) obj;
          if (predicate.test(t)) {
            return new Result.Success<>(t, seq.tailView());
          }
        }
      }
      return new Result.NoParse<>(seq);
    };
  }

  static  Parser satisfies2(final Class clazz, final Function> f) {
    return seq -> {
      if (seq.nonEmpty()) {
        final Object obj = seq.head();
        if (clazz.isAssignableFrom(obj.getClass())) {
          @SuppressWarnings("unchecked") final T t = (T) obj;
          final Optional result = f.apply(t);
          if (result.isPresent()) {
            return new Result.Success<>(result.get(), seq.tailView());
          }
        }
      }
      return new Result.NoParse<>(seq);
    };
  }

  static  Parser recurse(
    final Class clazz,
    final Predicate predicate,
    final Function> extractor,
    final Parser parser) {

    return seq -> {
      if (seq.nonEmpty()) {
        final Object obj = seq.head();
        if (clazz.isAssignableFrom(obj.getClass())) {
          @SuppressWarnings("unchecked") final T t = (T) obj;
          if (predicate.test(t)) {
            final Seq rseq = extractor.apply(t);
            final Result result = parser.parse(rseq);
            if (result.isSuccess()) {
              if (result.getRemaining().nonEmpty()) {
                return new Result.NoParse<>(seq);
              }
              return result.withRemaining(seq.tailView());
            }
            return result.withRemaining(seq);
          }
        }
      }
      return new Result.NoParse<>(seq);
    };
  }

  static  Parser recurse2(
    final Class clazz,
    final Function> extractor,
    final Function> parser) {

    return seq -> {
      if (seq.nonEmpty()) {
        final Object obj = seq.head();
        if (clazz.isAssignableFrom(obj.getClass())) {
          @SuppressWarnings("unchecked") final T t = (T) obj;
          final Seq rseq = extractor.apply(t);
          final Result result = parser.apply(t).parse(rseq);
          if (result.isSuccess()) {
            if (result.getRemaining().nonEmpty()) {
              return new Result.NoParse<>(seq);
            }
            return result.withRemaining(seq.tailView());
          }
          return result.withRemaining(seq);

        }
      }
      return new Result.NoParse<>(seq);
    };
  }

  static  Parser> optional(final Parser parser) {
    return seq -> {
      final Result result = parser.parse(seq);
      if (result.isNoParse()) {
        return new Result.Success<>(Optional.empty(), result.getRemaining());
      }
      return result.map(Optional::of);
    };
  }

  static  Parser option(final T fallback, final Parser parser) {
    return optional(parser).map(optional -> optional.orElse(fallback));
  }

  static  Parser option(final Supplier fallbackSupplier, final Parser parser) {
    return optional(parser).map(optional -> optional.orElseGet(fallbackSupplier));
  }

  @SafeVarargs
  static  Parser> sequence(final Parser... ps) {

    return seq -> {
      final SeqBuilder seqBuilder = Seq.builder();
      Seq remaining = seq;
      Result result;
      for (final Parser p : ps) {
        if (remaining.isEmpty()) {
          return new Result.NoParse<>(seq);
        }
        result = p.parse(remaining);
        if (!result.isSuccess()) {
          return result.withRemaining(seq).as();
        }
        remaining = result.getRemaining();
        seqBuilder.add(result.getValue());
      }
      return new Result.Success<>(seqBuilder.result(), remaining);
    };
  }

  static  Parser> sequence(final Iterable> ps) {

    return seq -> {
      final SeqBuilder seqBuilder = Seq.builder();
      Seq remaining = seq;
      Result result;
      for (final Parser p : ps) {
        if (remaining.isEmpty()) {
          return new Result.NoParse<>(seq);
        }
        result = p.parse(remaining);
        if (!result.isSuccess()) {
          return result.withRemaining(seq).as();
        }
        remaining = result.getRemaining();
        seqBuilder.add(result.getValue());
      }
      return new Result.Success<>(seqBuilder.result(), remaining);
    };
  }

  static  Parser> times(final int n, final Parser p) {

    return seq -> {
      final SeqBuilder seqBuilder = Seq.builder();
      Seq remaining = seq;
      Result result;
      for (int i = 0; i < n; i += 1) {
        if (remaining.isEmpty()) {
          return new Result.NoParse<>(seq);
        }
        result = p.parse(remaining);
        if (!result.isSuccess()) {
          return result.withRemaining(seq).as();
        }
        remaining = result.getRemaining();
        seqBuilder.add(result.getValue());
      }
      return new Result.Success<>(seqBuilder.result(), remaining);
    };
  }

  static  Parser> seq(
    final Parser p1,
    final Parser p2) {

    return seq -> {
      final Result r1 = p1.parse(seq);
      if (r1.isSuccess()) {
        final Result r2 = p2.parse(r1.getRemaining());
        if (r2.isSuccess()) {
          return new Result.Success<>(Pair.of(r1.getValue(), r2.getValue()), r2.getRemaining());
        }
        return r2.withRemaining(seq).as();
      }
      return r1.withRemaining(seq).as();
    };
  }

  static  Parser> seq(
    final Parser p1,
    final Parser p2,
    final Parser p3) {

    return seq -> {
      final Result r1 = p1.parse(seq);
      if (r1.isSuccess()) {
        final Result r2 = p2.parse(r1.getRemaining());
        if (r2.isSuccess()) {
          final Result r3 = p3.parse(r2.getRemaining());
          if (r3.isSuccess()) {
            return new Result.Success<>(
              Triple.of(r1.getValue(), r2.getValue(), r3.getValue()), r3.getRemaining()
            );
          }
          return r3.withRemaining(seq).as();
        }
        return r2.withRemaining(seq).as();
      }
      return r1.withRemaining(seq).as();
    };
  }

  static  Parser> seq(
    final Parser p1,
    final Parser p2,
    final Parser p3,
    final Parser p4) {

    return seq -> {
      final Result r1 = p1.parse(seq);
      if (r1.isSuccess()) {
        final Result r2 = p2.parse(r1.getRemaining());
        if (r2.isSuccess()) {
          final Result r3 = p3.parse(r2.getRemaining());
          if (r3.isSuccess()) {
            final Result r4 = p4.parse(r3.getRemaining());
            if (r4.isSuccess()) {
              return new Result.Success<>(
                Quadruple.of(r1.getValue(), r2.getValue(), r3.getValue(), r4.getValue()), r4.getRemaining()
              );
            }
            return r4.withRemaining(seq).as();
          }
          return r3.withRemaining(seq).as();
        }
        return r2.withRemaining(seq).as();
      }
      return r1.withRemaining(seq).as();
    };
  }

  static  Parser> many(final Parser parser) {
    return seq -> {
      final SeqBuilder resultBuilder = Seq.builder();
      Seq remaining = seq;
      while (remaining.nonEmpty()) {
        final Result result = parser.parse(remaining);
        if (!result.isSuccess()) {
          return new Result.Success<>(resultBuilder.result(), remaining);
        }
        resultBuilder.add(result.getValue());
        remaining = result.getRemaining();
      }
      return new Result.Success<>(resultBuilder.result(), remaining);
    };
  }

  static  Parser> many1(final Parser parser) {
    final Parser> manyParser = many(parser);
    return seq -> {
      final Result> result = manyParser.parse(seq);
      if (result.isSuccess() && result.getValue().isEmpty()) {
        return new Result.NoParse<>(seq);
      }
      return result;
    };
  }

  static  Parser skipMany(final Parser parser) {
    return seq -> {
      Seq remaining = seq;
      while (remaining.nonEmpty()) {
        final Result result = parser.parse(remaining);
        if (!result.isSuccess()) {
          return new Result.Success<>(null, remaining);
        }
        remaining = result.getRemaining();
      }
      return new Result.Success<>(null, remaining);
    };
  }

  static  Parser> sepBy(final Parser parser, final Parser sep) {
    final Parser p = right(sep, parser);
    return seq -> {
      final SeqBuilder resultBuilder = Seq.builder();
      Seq remaining = seq;
      Result result = parser.parse(remaining);
      if (result.isSuccess()) {
        resultBuilder.add(result.getValue());
        remaining = result.getRemaining();
        while (remaining.nonEmpty()) {
          result = p.parse(remaining);
          if (!result.isSuccess()) {
            return new Result.Success<>(resultBuilder.result(), remaining);
          }
          resultBuilder.add(result.getValue());
          remaining = result.getRemaining();
        }
      }
      return new Result.Success<>(resultBuilder.result(), remaining);
    };
  }

  static  Parser> sepBy1(final Parser parser, final Parser sep) {
    final Parser> sepByParser = sepBy(parser, sep);
    return seq -> {
      final Result> result = sepByParser.parse(seq);
      if (result.isSuccess() && result.getValue().isEmpty()) {
        return new Result.NoParse<>(seq);
      }
      return result;
    };
  }

  /**
   * Creates a parser that is constructed at first invocation for recursive invocation
   * of the parser.
   */
  static  Parser recursive(final Supplier> supplier) {
    final Supplier> parserSupplier = Control.memoizing(supplier);
    return seq -> parserSupplier.get().parse(seq);
  }

  static  boolean shuntingYard(
    final Iterable in,
    final Consumer out,
    final Mapping precedenceMap,
    final Predicate isLeftAssociative,
    final Predicate isLeftBracket,
    final Predicate isRightBracket
  ) {
    return shuntingYard(
      in,
      out,
      precedenceMap.keys()::contains,
      (a, b) -> precedenceMap.apply(a) > precedenceMap.apply(b),
      (a, b) -> precedenceMap.apply(a).equals(precedenceMap.apply(b)),
      isLeftAssociative,
      isLeftBracket,
      isRightBracket
    );
  }

  static  boolean shuntingYard(
    final Iterable in,
    final Consumer out,
    final Predicate isOperator,
    final BiPredicate hasHigherPrecedenceThan,
    final BiPredicate hasEqualPrecedenceAs,
    final Predicate isLeftAssociative,
    final Predicate isLeftBracket,
    final Predicate isRightBracket
  ) {
    final Deque stack = new ArrayDeque<>();
    for (final T s : in) {
      if (isOperator.test(s)) {
        while (!stack.isEmpty() && isOperator.test(stack.peek()) &&
          (hasHigherPrecedenceThan.test(stack.peek(), s)
            || (hasEqualPrecedenceAs.test(stack.peek(), s) && isLeftAssociative.test(stack.peek())))) {
          out.accept(stack.pop());
        }
        stack.push(s);
      } else if (isLeftBracket.test(s)) {
        stack.push(s);
      } else if (isRightBracket.test(s)) {
        while (!stack.isEmpty() && !isLeftBracket.test(stack.peek())) {
          out.accept(stack.pop());
        }
        if (!stack.isEmpty() && isLeftBracket.test(stack.peek())) {
          stack.pop();
        } else {
          return false;
        }
      } else {
        out.accept(s);
      }
    }
    while (!stack.isEmpty()) {
      final T t = stack.pop();
      if (!isOperator.test(t)) {
        return false;
      }
      out.accept(t);
    }
    return true;
  }
}