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

com.vladsch.flexmark.util.visitor.AstActionHandler Maven / Gradle / Ivy

The newest version!
package com.vladsch.flexmark.util.visitor;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
 * Intended to be completed by subclasses for specific node types and node actions
 *
 * @param  subclass of this class to have functions returning this to have the correct type
 * @param  base node type, this class does not care but in specific handlers it should be a
 *     common supertype for all nodes
 * @param  action type, subclasses of {@link AstAction} and {@link AstHandler} provide actual
 *     functionality
 * @param  handler to invoke the functionality during AST traversal for specific node
 */
public abstract class AstActionHandler<
    C extends AstActionHandler, N, A extends AstAction, H extends AstHandler> {
  private final @NotNull Map, H> customHandlersMap = new HashMap<>();
  private final @NotNull AstNode astAdapter;

  public AstActionHandler(@NotNull AstNode astAdapter) {
    this.astAdapter = astAdapter;
  }

  @SafeVarargs
  protected final @NotNull C addActionHandlers(@NotNull H[]... handlers) {
    for (H[] moreHandlers : handlers) {
      for (H handler : moreHandlers) {
        customHandlersMap.put(handler.getNodeType(), handler);
      }
    }
    return (C) this;
  }

  protected @NotNull C addActionHandler(@NotNull H handler) {
    customHandlersMap.put(handler.getNodeType(), handler);
    return (C) this;
  }

  private @Nullable A getAction(@Nullable H handler) {
    return handler == null ? null : handler.getAdapter();
  }

  public @Nullable A getAction(@NotNull N node) {
    return getAction(customHandlersMap.get(node.getClass()));
  }

  public @Nullable A getAction(@NotNull Class nodeClass) {
    return getAction(customHandlersMap.get(nodeClass));
  }

  protected @Nullable H getHandler(@NotNull N node) {
    return customHandlersMap.get(node.getClass());
  }

  protected @Nullable H getHandler(@NotNull Class nodeClass) {
    return customHandlersMap.get(nodeClass);
  }

  public @NotNull Set> getNodeClasses() {
    return customHandlersMap.keySet();
  }

  /**
   * Node processing called for every node being processed
   *
   * 

Override this to add customizations to standard processing callback. * * @param node node being processed * @param withChildren whether to process child nodes if there is no handler for the node type * @param processor processor to invoke to perform the processing, BiConsumer taking N node, and A * action */ protected void processNode( @NotNull N node, boolean withChildren, @NotNull BiConsumer processor) { A action = getAction(node); if (action != null) { processor.accept(node, action); } else if (withChildren) { processChildren(node, processor); } } protected final void processChildren(@NotNull N node, @NotNull BiConsumer processor) { N child = astAdapter.getFirstChild(node); while (child != null) { // A subclass of this visitor might modify the node, resulting in getNext returning a // different node or no // node after visiting it. So get the next node before visiting. N next = astAdapter.getNext(child); processNode(child, true, processor); child = next; } } /** * Process the node and return value from the processor * * @param node node to process * @param defaultValue default value if no handler is defined for the node * @param processor processor to pass the node and handler for processing * @param type of result returned by processor * @return result or defaultValue */ protected final R processNodeOnly( @NotNull N node, R defaultValue, @NotNull BiFunction processor) { Object[] value = {defaultValue}; processNode(node, false, (n, h) -> value[0] = processor.apply(n, h)); return (R) value[0]; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy