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

org.immutables.trees.ast.Extractions Maven / Gradle / Ivy

There is a newer version: 2.2.12
Show newest version
/*
   Copyright 2016 Immutables Authors and Contributors

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */
package org.immutables.trees.ast;

import com.google.common.base.Function;
import com.google.common.base.Joiner;
import org.parboiled.Action;
import org.parboiled.Context;
import org.parboiled.errors.ErrorUtils;
import org.parboiled.support.Position;

/**
 * Parboiled extraction for the sake of AST building.
 */
public final class Extractions {
  private Extractions() {}

  public interface Extractor {
    T get(Context context);
  }

  public interface Applicator extends Action {}

  public static  Extractor value(final T value) {
    return new Extractor() {
      @Override
      public T get(Context context) {
        return value;
      }

      @Override
      public String toString() {
        return Extractions.class.getSimpleName() + ".value(" + value + ")";
      }
    };
  }

  public static Extractor matched() {
    return MatchExtractor.INSTANCE;
  }

  public static Extractor position() {
    return PositionExtractor.INSTANCE;
  }

  // safe unchecked: will always work with any kind of object
  @SuppressWarnings("unchecked")
  public static  Extractor popped() {
    return (Extractor) PopExtractor.INSTANCE;
  }

  public static  Extractor popped(final Function transform) {
    return new Extractor() {
      @Override
      public T get(Context context) {
        return transform.apply(Extractions.popped().get(context));
      }

      @Override
      public String toString() {
        return Extractions.class.getSimpleName() + ".popped(" + transform + ")";
      }
    };
  }

  private enum MatchExtractor implements Extractor {
    INSTANCE;
    @Override
    public String get(Context context) {
      return context.getMatch();
    }

    @Override
    public String toString() {
      return Extractions.class.getSimpleName() + ".matched()";
    }
  }

  private enum PositionExtractor implements Extractor {
    INSTANCE;
    @Override
    public Position get(Context context) {
      return context.getPosition();
    }

    @Override
    public String toString() {
      return Extractions.class.getSimpleName() + ".position()";
    }
  }

  private enum PopExtractor implements Extractor, Applicator {
    INSTANCE;
    @Override
    public Object get(Context context) {
      return context.getValueStack().pop();
    }

    @Override
    public boolean run(Context context) {
      get(context);
      return true;
    }

    @Override
    public String toString() {
      return Extractions.class.getSimpleName() + ".popped()";
    }
  }

  public static Applicator print() {
    return new Applicator() {
      @Override
      public boolean run(Context context) {
        printContext(this, context);
        return true;
      }

      @Override
      public String toString() {
        return Extractions.class.getSimpleName() + ".print()";
      }
    };
  }

  static abstract class ExtractorApplicator implements Extractor, Applicator {
    @Override
    public final boolean run(Context context) {
      Object value = get(context);
      context.getValueStack().push(value);
      return true;
    }
  }

  public static abstract class Instance extends ExtractorApplicator {
    @Override
    public T get(Context context) {
      return get();
    }

    public abstract T get();
  }

  public static abstract class Construct extends ExtractorApplicator {
    private final Extractor extractor;

    protected Construct(Extractor extractor) {
      this.extractor = extractor;
    }

    @Override
    public final T get(Context context) {
      V value = extractor.get(context);
      return get(value);
    }

    public abstract T get(V value);
  }

  public static abstract class Specify implements Applicator {
    private final Extractor extractor;

    protected Specify(Extractor extractor) {
      this.extractor = extractor;
    }

    @Override
    public final boolean run(Context context) {
      V value = extractor.get(context);
      @SuppressWarnings("unchecked")
      B builder = (B) context.getValueStack().peek();
      specify(builder, value);
      return true;
    }

    public abstract void specify(B builder, V value);
  }

  public static abstract class Build extends ExtractorApplicator {

    @Override
    public final T get(Context context) {
      @SuppressWarnings("unchecked")
      B builder = (B) context.getValueStack().pop();
      return build(builder);
    }

    public abstract T build(B builder);
  }

  public static abstract class Builder implements Applicator {
    @Override
    public final boolean run(Context context) {
      B builder = builder();
      context.getValueStack().push(builder);
      return true;
    }

    public abstract B builder();
  }

  private static void printContext(Object caller, Context context) {
    String message = ErrorUtils.printErrorMessage("%s:%s:%s",
        "",
        context.getCurrentIndex(),
        context.getCurrentIndex() + 1,
        context.getInputBuffer());
    System.err.println("*** " + caller + message + "\n\t" + Joiner.on("\n\t - ").join(context.getValueStack()));
  }
}