package org.jastadd.ag.ast;

import java.util.*;
/** @apilevel internal 
 * @ast class
 * @declaredat ASTState:34
 */
public class ASTState extends java.lang.Object {
  /**
   * This class stores an attribute value tagged with an iteration ID for
   * a circular evaluation.
   * 
   * @apilevel internal
   * @declaredat ASTState:41
   */
  
  /**
   * This class stores an attribute value tagged with an iteration ID for
   * a circular evaluation.
   *
   * @apilevel internal
   */
  protected static class CircularValue {
    Object value;
    Cycle cycle;
  }
  /**
   * Instances of this class are used to uniquely identify circular evaluation iterations.
   * These iteration ID objects are created for each new fixed-point iteration in
   * a circular evaluation.
   * 
   * @apilevel internal
   * @declaredat ASTState:53
   */
  

  /**
   * Instances of this class are used to uniquely identify circular evaluation iterations.
   * These iteration ID objects are created for each new fixed-point iteration in
   * a circular evaluation.
   *
   * @apilevel internal
   */
  protected static class Cycle {
  }
  /**
   * The iteration ID used outside of circular evaluation.
   * 
   * <p>This is the iteration ID when no circular evaluation is ongoing.
   * @declaredat ASTState:61
   */
  

  /**
   * The iteration ID used outside of circular evaluation.
   *
   * <p>This is the iteration ID when no circular evaluation is ongoing.
   */
  public static final Cycle NON_CYCLE = new Cycle();
  /**
   * Tracks the state of the current circular evaluation. This class defines a
   * stack structure where the next element on the stack is pointed to by the
   * {@code next} field.
   * 
   * @apilevel internal
   * @declaredat ASTState:70
   */
  

  /**
   * Tracks the state of the current circular evaluation. This class defines a
   * stack structure where the next element on the stack is pointed to by the
   * {@code next} field.
   *
   * @apilevel internal
   */
  protected static class CircleState {
    final CircleState next;
    boolean change = false;

    /** Evaluation depth of lazy attributes. */
    int lazyAttribute = 0;

    /** Cycle ID of the latest cycle in this circular evaluation. */
    Cycle cycle = NON_CYCLE;


    protected CircleState(CircleState next) {
      this.next = next;
    }
  }
  /** Sentinel circle state representing non-circular evaluation. 
   * @declaredat ASTState:88
   */
  


  /** Sentinel circle state representing non-circular evaluation. */
  private static final CircleState CIRCLE_BOTTOM = new CircleState(null);
  /**
   * Current circular state.
   * @apilevel internal
   * @declaredat ASTState:94
   */
  

  /**
   * Current circular state.
   * @apilevel internal
   */
  private CircleState circle = CIRCLE_BOTTOM;
  /** @apilevel internal 
   * @declaredat ASTState:97
   */
  

  /** @apilevel internal */
  protected boolean inCircle() {
    return circle != CIRCLE_BOTTOM;
  }
  /** @apilevel internal 
   * @declaredat ASTState:102
   */
  

  /** @apilevel internal */
  protected boolean calledByLazyAttribute() {
    return circle.lazyAttribute > 0;
  }
  /** @apilevel internal 
   * @declaredat ASTState:107
   */
  

  /** @apilevel internal */
  protected void enterLazyAttribute() {
    circle.lazyAttribute += 1;
  }
  /** @apilevel internal 
   * @declaredat ASTState:112
   */
  

  /** @apilevel internal */
  protected void leaveLazyAttribute() {
    circle.lazyAttribute -= 1;
  }
  /** @apilevel internal 
   * @declaredat ASTState:117
   */
  

  /** @apilevel internal */
  protected void enterCircle() {
    CircleState next = new CircleState(circle);
    circle = next;
  }
  /**
   * Maps circular attribute to last evaluated cycle index.
   * @apilevel internal
   * @declaredat ASTState:127
   */
  


  /**
   * Maps circular attribute to last evaluated cycle index.
   * @apilevel internal
   */
  private java.util.Map<Object, Integer> visited = new java.util.IdentityHashMap<Object, Integer>();
  /**
   * Check if attribute was already visited during the current cycle.
   * @apilevel internal
   * @return {@code true} if the attribute was already visited.
   * @declaredat ASTState:134
   */
  

  /**
   * Check if attribute was already visited during the current cycle.
   * @apilevel internal
   * @return {@code true} if the attribute was already visited.
   */
  protected boolean checkAndSetVisited(Object attribute, int cycle) {
    boolean result = visited.containsKey(attribute) && visited.get(attribute) == cycle;
    visited.put(attribute, cycle);
    return result;
  }
  /**
   * Reset visited cycle tracking for this thread.
   * @apilevel internal
   * @declaredat ASTState:144
   */
  

  /**
   * Reset visited cycle tracking for this thread.
   * @apilevel internal
   */
  protected void clearVisited() {
    visited.clear();
  }
  /**
   * Reset visit tracker for a single attribute.
   * @apilevel internal
   * @declaredat ASTState:153
   */
  

  // TODO(joqvist): may not be necessary.
  /**
   * Reset visit tracker for a single attribute.
   * @apilevel internal
   */
  protected void resetVisited(Object attribute) {
    visited.remove(attribute);
  }
  /** @apilevel internal 
   * @declaredat ASTState:158
   */
  

  /** @apilevel internal */
  protected void leaveCircle() {
    circle = circle.next;
  }
  /** @apilevel internal 
   * @declaredat ASTState:163
   */
  

  /** @apilevel internal */
  protected Cycle nextCycle() {
    Cycle cycle = new Cycle();
    circle.cycle = cycle;
    return cycle;
  }
  /** @apilevel internal 
   * @declaredat ASTState:170
   */
  

  /** @apilevel internal */
  protected Cycle cycle() {
    return circle.cycle;
  }
  /** @apilevel internal 
   * @declaredat ASTState:175
   */
  

  /** @apilevel internal */
  protected CircleState currentCircle() {
    return circle;
  }
  /** @apilevel internal 
   * @declaredat ASTState:181
   */
  


  /** @apilevel internal */
  protected void setChangeInCycle() {
    circle.change = true;
  }
  /** @apilevel internal 
   * @declaredat ASTState:186
   */
  

  /** @apilevel internal */
  protected boolean testAndClearChangeInCycle() {
    boolean change = circle.change;
    circle.change = false;
    return change;
  }
  /** @apilevel internal 
   * @declaredat ASTState:193
   */
  

  /** @apilevel internal */
  protected boolean changeInCycle() {
    return circle.change;
  }
  /**
   * @declaredat ASTState:198
   */
  


  protected ASTState() {
  }
  /**
   * @declaredat ASTState:202
   */
  
  
  
    protected java.util.Stack handlerAttrStack = new java.util.Stack();
  /**
   * @declaredat ASTState:204
   */
  
  
    public void addHandlerDepTo(ASTNode$DepGraphNode handler) {
      if (!IN_ATTR_STORE_EVAL || handler == null) {
        return;
      }
      java.util.Stack handlerStack = handlerAttrStack;
      if (!handlerStack.isEmpty()) {
        ASTNode$DepGraphNode top = (ASTNode$DepGraphNode) handlerStack.peek();
        handler.addListener(top);
  
      }
    }
  /**
   * @declaredat ASTState:216
   */
  
  
    public boolean IN_ATTR_STORE_EVAL = false;
  /**
   * @declaredat ASTState:218
   */
  
  
    public void enterAttrStoreEval(ASTNode$DepGraphNode handler) {
      IN_ATTR_STORE_EVAL = true;
      pushHandler(handlerAttrStack, handler);
      handler.setComputed();
    }
  /**
   * @declaredat ASTState:224
   */
  
  
    public void exitAttrStoreEval(ASTNode$DepGraphNode handler) {
      popHandler(handlerAttrStack, handler);
      IN_ATTR_STORE_EVAL = !handlerAttrStack.isEmpty();
    }
  /**
   * @declaredat ASTState:229
   */
  
  
    public void enterRewriteEval(ASTNode$DepGraphNode handler) {
      enterAttrStoreEval(handler);
    }
  /**
   * @declaredat ASTState:233
   */
  
  
    public void exitRewriteEval(ASTNode$DepGraphNode handler) {
      exitAttrStoreEval(handler);
    }
  /**
   * @declaredat ASTState:237
   */
  
  
    public int disableDeps = 0;
  /**
   * @declaredat ASTState:239
   */
  
  
    public void enterConstruction() {
      disableDeps++;
    }
  /**
   * @declaredat ASTState:243
   */
  
  
    public void exitConstruction() {
      disableDeps--;
    }
  /**
   * @declaredat ASTState:247
   */
  
  
    protected void pushHandler(java.util.Stack stack, ASTNode$DepGraphNode handler) {
      stack.push(handler);
    }
  /**
   * @declaredat ASTState:251
   */
  
  
    protected ASTNode$DepGraphNode popHandler(java.util.Stack stack, ASTNode$DepGraphNode handler) {
      if (stack.isEmpty()) {
        throw new Error("Handler stack is empty at exit!");
      }
      ASTNode$DepGraphNode h = (ASTNode$DepGraphNode)stack.pop();
      if (h != handler) {
        throw new Error("Top of handler stack does not match at pop!");
      }
      return h;
    }
  /**
   * @declaredat ASTState:262
   */
  

  public interface ReceiverFactory {
    Trace.Receiver build();
  }
  /**
   * @declaredat ASTState:266
   */
  

  public static ReceiverFactory receiverFactory = new ReceiverFactory() {
    public Trace.Receiver build() {
      return new Trace.Receiver() {
        public void accept(ASTState.Trace.Event event, ASTNode node, String attribute,
            Object params, Object value) {
        }
      };
    }
  };
  /**
   * @declaredat ASTState:276
   */
  

  private Trace trace = null;
  /** @return the tracer instance used for tracing attribute evaluation in this AST. 
   * @declaredat ASTState:279
   */
  

  /** @return the tracer instance used for tracing attribute evaluation in this AST. */
  public Trace trace() {
    if (trace == null) {
      trace = new Trace(receiverFactory.build());
    }
    return trace;
  }
  /**
   * @declaredat ASTState:286
   */
  

  public static class Trace {
    /**
     * Trace events corresponding to attribute evaluation events.
     *
     * <p>These events can be filtered statically using the flag --tracing to
     * JastAdd2. For example, the flag {@code --tracing=compute,cache} will only trace
     * compute events and cache events. The flag --tracing will enable all events.
     *
     * <p>To access the trace events you will need to register an event receiver.
     * This can be done using the method setReceiver(ASTState.Trace.Receiver).
     */
    public enum Event {
      // Flag: --tracing=compute
      COMPUTE_BEGIN,
      COMPUTE_END,
  
      // Flag: --tracing=cache
      CACHE_WRITE,
      CACHE_READ,
      CACHE_ABORT,
  
      // Flag: --tracing=rewrite
      REWRITE_CASE1_START,
      REWRITE_CASE1_CHANGE,
      REWRITE_CASE1_RETURN,
      REWRITE_CASE2_RETURN,
      REWRITE_CASE3_RETURN,
  
      // Flag: --tracing=circular
      CIRCULAR_NTA_CASE1_START,
      CIRCULAR_NTA_CASE1_CHANGE,
      CIRCULAR_NTA_CASE1_RETURN,
      CIRCULAR_NTA_CASE2_START,
      CIRCULAR_NTA_CASE2_CHANGE,
      CIRCULAR_NTA_CASE2_RETURN,
      CIRCULAR_NTA_CASE3_RETURN,
      CIRCULAR_CASE1_START,
      CIRCULAR_CASE1_CHANGE,
      CIRCULAR_CASE1_RETURN,
      CIRCULAR_CASE2_START,
      CIRCULAR_CASE2_CHANGE,
      CIRCULAR_CASE2_RETURN,
      CIRCULAR_CASE3_RETURN,
  
      // Flag: --tracing=copy
      COPY_NODE,
  
      // Flag: --tracing=flush
      FLUSH_ATTR,
      FLUSH_REWRITE,
      FLUSH_REWRITE_INIT,
      INC_FLUSH_ATTR,
  
      // Flag: --tracing=coll
      CONTRIBUTION_CHECK_BEGIN,
      CONTRIBUTION_CHECK_MATCH,
      CONTRIBUTION_CHECK_END,
      
      // Flag: --tracing=token
      TOKEN_READ;
    }
  
    /**
     * Functional interface for a trace event receiver.
     * This can be implemented by applications that want to trace attribute evaluation.
     */
    public interface Receiver {
      void accept(ASTState.Trace.Event event, ASTNode node, String attribute,
          Object params, Object value);
    }
  
    public Trace(Receiver receiver) {
      this.receiver = receiver;
    }
  
    public Trace() {
    }
  
    // The default event receiver does nothing.
    private Receiver receiver = new Receiver() {
      public void accept(ASTState.Trace.Event event, ASTNode node, String attribute,
          Object params, Object value) {
      }
    };
  
    /**
     * Registers an input filter to use during tracing.
     * @param filter The input filter to register.
     */
    public void setReceiver(ASTState.Trace.Receiver receiver) {
      this.receiver = receiver;
    }
  
    public Receiver getReceiver() {
      return receiver;
    }
  
    /**
     * Trace that an attribute instance started its computation.
     * @param value The value of the attribute instance.
     */
    public void computeBegin(ASTNode node, String attr, Object params, Object value) {
      receiver.accept(Event.COMPUTE_BEGIN, node, attr, params, value);
    }
  
    /**
     * Trace that an attribute instance ended its computation.
     * @param value The value of the attribute instance.
     */
    public void computeEnd(ASTNode node, String attr, Object params, Object value) {
      receiver.accept(ASTState.Trace.Event.COMPUTE_END, node, attr, params, value);
    }
  
    /**
     * Trace that the cache of an attribute instances was read.
     * @param value The value of the attribute instance.
     */
    public void cacheRead(ASTNode node, String attr, Object params, Object value) {
      receiver.accept(ASTState.Trace.Event.CACHE_READ, node, attr, params, value);
    }
  
    /**
     * Trace that an attribute instance was cached.
     * @param value The value of the attribute instance.
     */
    public void cacheWrite(ASTNode node, String attr, Object params, Object value) {
      receiver.accept(ASTState.Trace.Event.CACHE_WRITE, node, attr, params, value);
    }
  
    /**
     * Trace that the caching of an attribute instance was aborted.
     * @param value The value of the attribute instance.
     */
    public void cacheAbort(ASTNode node, String attr, Object params, Object value) {
      receiver.accept(ASTState.Trace.Event.CACHE_ABORT, node, attr, params, value);
    }
  
    /**
     * Trace that a rewrite evaluation entered case 1.
     * @param value The value of the rewrite.
     */
    public void enterRewriteCase1(ASTNode node, String attr, Object params, Object value) {
      receiver.accept(ASTState.Trace.Event.REWRITE_CASE1_START, node, attr, params, value);
    }
  
    /**
     * Trace that a rewrite in evaluation case 1 changed value.
     * @param value The value of the rewrite before and after.
     */
    public void rewriteChange(ASTNode node, String attr, Object params, Object value) {
      receiver.accept(ASTState.Trace.Event.REWRITE_CASE1_CHANGE, node, attr, params, value);
    }
  
    /**
     * Trace that a rewrite returned from evaluation case 1.
     * @param value The value of the rewrite.
     */
    public void exitRewriteCase1(ASTNode node, String attr, Object params, Object value) {
      receiver.accept(ASTState.Trace.Event.REWRITE_CASE1_RETURN, node, attr, params, value);
    }
  
    /**
     * Trace that a rewrite returned from evaluation case 2.
     * @param value The value of the rewrite.
     */
    public void exitRewriteCase2(ASTNode node, String attr, Object params, Object value) {
      receiver.accept(ASTState.Trace.Event.REWRITE_CASE2_RETURN, node, attr, params, value);
    }
  
    /**
     * Trace that a rewrite returned from evaluation case 3.
     * @param value The value of the rewrite.
     */
    public void exitRewriteCase3(ASTNode node, String attr, Object params, Object value) {
      receiver.accept(ASTState.Trace.Event.REWRITE_CASE3_RETURN, node, attr, params, value);
    }
  
    /**
     * Trace that a circular attribute instance entered evaluation case 1.
     * @param value The value of the circular attribute instance.
     */
    public void enterCircularCase1(ASTNode node, String attr, Object params, Object value) {
      receiver.accept(ASTState.Trace.Event.CIRCULAR_CASE1_START, node, attr, params, value);
    }
  
    /**
     * Trace that a circular attribute instance in evaluation case 1 changed value.
     * @param value The value of the circular attribute instance, before and after.
     */
    public void circularCase1Change(ASTNode node, String attr, Object params, Object value) {
      receiver.accept(ASTState.Trace.Event.CIRCULAR_CASE1_CHANGE, node, attr, params, value);
    }
  
    /**
     * Trace that a circular attribute instance returned from evaluation case 1.
     * @param value The value of the circular attribute instance.
     */
    public void exitCircularCase1(ASTNode node, String attr, Object params, Object value) {
      receiver.accept(ASTState.Trace.Event.CIRCULAR_CASE1_RETURN, node, attr, params, value);
    }
  
    /**
     * Trace that a circular attribute instance entered evaluation case 2.
     * @param value The value of the circular attribute instance.
     */
    public void enterCircularCase2(ASTNode node, String attr, Object params, Object value) {
      receiver.accept(ASTState.Trace.Event.CIRCULAR_CASE2_START, node, attr, params, value);
    }
  
    /**
     * Trace that a circular attribute instance in evaluation case 2 changed value.
     * @param value The value of the circular attribute instance, before and after.
     */
    public void circularCase2Change(ASTNode node, String attr, Object params, Object value) {
      receiver.accept(ASTState.Trace.Event.CIRCULAR_CASE2_CHANGE, node, attr, params, value);
    }
  
    /**
     * Trace that a circular attribute instance returned from evaluation case 2.
     * @param value The value of the circular attribute instance.
     */
    public void exitCircularCase2(ASTNode node, String attr, Object params, Object value) {
      receiver.accept(ASTState.Trace.Event.CIRCULAR_CASE2_RETURN, node, attr, params, value);
    }
  
    /**
     * Trace that a circular attribute instance returned from evaluation case 2.
     * @param value The value of the circular attribute instance.
     */
    public void exitCircularCase3(ASTNode node, String attr, Object params, Object value) {
      receiver.accept(ASTState.Trace.Event.CIRCULAR_CASE3_RETURN, node, attr, params, value);
    }
  
    /**
     * Trace that a circular NTA entered evaluation case 1.
     * @param value The value of the circular NTA.
     */
    public void enterCircularNTACase1(ASTNode node, String attr, Object params, Object value) {
      receiver.accept(ASTState.Trace.Event.CIRCULAR_NTA_CASE1_START, node, attr, params, value);
    }
  
    /**
     * Trace that a circular NTA in evaluation case 1 changed value.
     * @param value The value of the circular NTA, before and after.
     */
    public void circularNTACase1Change(ASTNode node, String attr, Object params, Object value) {
      receiver.accept(ASTState.Trace.Event.CIRCULAR_NTA_CASE1_CHANGE, node, attr, params, value);
    }
  
    /**
     * Trace that a circular NTA returned from evaluation case 1.
     * @param value The value of the circular NTA.
     */
    public void exitCircularNTACase1(ASTNode node, String attr, Object params, Object value) {
      receiver.accept(ASTState.Trace.Event.CIRCULAR_NTA_CASE1_RETURN, node, attr, params, value);
    }
  
    /**
     * Trace that a circular NTA entered evaluation case 2.
     * @param value The value of the circular NTA.
     */
    public void enterCircularNTACase2(ASTNode node, String attr, Object params, Object value) {
      receiver.accept(ASTState.Trace.Event.CIRCULAR_NTA_CASE2_START, node, attr, params, value);
    }
  
    /**
     * Trace that a circular NTA in evaluation case 2 changed value.
     * @param value The value of the circular NTA, before and after.
     */
    public void circularNTACase2Change(ASTNode node, String attr, Object params, Object value) {
      receiver.accept(ASTState.Trace.Event.CIRCULAR_NTA_CASE2_CHANGE, node, attr, params, value);
    }
  
    /**
     * Trace that a circular NTA returned from evaluation case 2.
     * @param value The value of the circular NTA.
     */
    public void exitCircularNTACase2(ASTNode node, String attr, Object params, Object value) {
      receiver.accept(ASTState.Trace.Event.CIRCULAR_NTA_CASE2_RETURN, node, attr, params, value);
    }
  
    /**
     * Trace that a circular NTA returned from evaluation case 2.
     * @param value The value of the circular NTA.
     */
    public void exitCircularNTACase3(ASTNode node, String attr, Object params, Object value) {
      receiver.accept(ASTState.Trace.Event.CIRCULAR_NTA_CASE3_RETURN, node, attr, params, value);
    }
  
    /**
     * Trace that an AST node was copied.
     * @param node The copied node.
     * @param value The value of the node.
     */
    public void copyNode(ASTNode node, Object value) {
      receiver.accept(ASTState.Trace.Event.COPY_NODE, node, "ASTNode.copy", "", value);
    }
  
    /**
     * Trace that an attribute was flushed.
     * @param value The value of the attribute.
     */
    public void flushAttr(ASTNode node, String attr, Object params, Object value) {
      receiver.accept(ASTState.Trace.Event.FLUSH_ATTR, node, attr, params, value);
    }
  
    /**
     * Trace that an attribute was flushed by incremental evaluation.
     */
    public void flushIncAttr(ASTNode node, String attr, Object params, Object value) {
      receiver.accept(ASTState.Trace.Event.INC_FLUSH_ATTR, node, attr, params, value);
    }
  
    /**
     * Trace that a contribution check to a collection attribute begun.
     */
    public void contributionCheckBegin(ASTNode node, String attr, String check) {
      receiver.accept(ASTState.Trace.Event.CONTRIBUTION_CHECK_BEGIN, node, attr, check, "");
    }
  
    /**
     * Trace that a contribution check to a collection attribute ended.
     */
    public void contributionCheckEnd(ASTNode node, String attr, String check) {
      receiver.accept(ASTState.Trace.Event.CONTRIBUTION_CHECK_END, node, attr, check, "");
    }
  
    /**
     * Trace that a contribution check to a collection attribute found a match.
     */
    public void contributionCheckMatch(ASTNode node, String attr, String check, Object value) {
      receiver.accept(ASTState.Trace.Event.CONTRIBUTION_CHECK_MATCH, node, attr, check, value);
    }
  
    /**
     * Trace that a token was read.
     */
    public void tokenRead(ASTNode node, String token, Object value) {
      receiver.accept(ASTState.Trace.Event.TOKEN_READ, node, token, "", value);
    }
  
  }
  /** @apilevel internal 
   * @declaredat ASTNode:432
   */
  public void reset() {
    // Reset circular evaluation state.
    circle = CIRCLE_BOTTOM;
  }

}