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

org.petitparser.utils.Mirror Maven / Gradle / Ivy

There is a newer version: 2.4.0
Show newest version
package org.petitparser.utils;

import org.petitparser.parser.Parser;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.Function;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

/**
 * A reflective parser mirror.
 */
public class Mirror implements Iterable {

  /**
   * Constructs a mirror of the provided {@code parser}.
   */
  public static Mirror of(Parser parser) {
    return new Mirror(parser);
  }

  private final Parser parser;

  private Mirror(Parser parser) {
    this.parser = Objects.requireNonNull(parser, "Undefined parser");
  }

  @Override
  public String toString() {
    return getClass().getSimpleName() + " of " + parser.toString();
  }

  /**
   * Returns an {@link Iterator} over {@code parser} and all its reachable descendants.
   */
  @Override
  public Iterator iterator() {
    return new ParserIterator(parser);
  }

  private static class ParserIterator implements Iterator {

    private final List todo = new ArrayList<>();
    private final Set seen = new HashSet<>();

    private ParserIterator(Parser root) {
      todo.add(root);
      seen.add(root);
    }

    @Override
    public boolean hasNext() {
      return !todo.isEmpty();
    }

    @Override
    public Parser next() {
      if (todo.isEmpty()) {
        throw new NoSuchElementException();
      }
      Parser current = todo.remove(todo.size() - 1);
      for (Parser parser : current.getChildren()) {
        if (!seen.contains(parser)) {
          todo.add(parser);
          seen.add(parser);
        }
      }
      return current;
    }
  }

  /**
   * Returns a {@link Stream} over {@code parser} and all its reachable descendants.
   */
  public Stream stream() {
    return StreamSupport.stream(
        Spliterators.spliteratorUnknownSize(iterator(), Spliterator.DISTINCT | Spliterator.NONNULL),
        false);
  }

  /**
   * Returns a transformed copy of all parsers reachable from {@code parser}.
   */
  public Parser transform(Function transformer) {
    Map mapping = new HashMap<>();
    for (Parser parser : this) {
      mapping.put(parser, transformer.apply(parser.copy()));
    }
    Set seen = new HashSet<>(mapping.values());
    List todo = new ArrayList<>(mapping.values());
    while (!todo.isEmpty()) {
      Parser parent = todo.remove(todo.size() - 1);
      for (Parser child : parent.getChildren()) {
        if (mapping.containsKey(child)) {
          parent.replace(child, mapping.get(child));
        } else if (!seen.contains(child)) {
          seen.add(child);
          todo.add(child);
        }
      }
    }
    return mapping.get(parser);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy