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

com.google.common.css.compiler.ast.CssNode Maven / Gradle / Ivy

Go to download

Closure Stylesheets is an extension to CSS that adds variables, functions, conditionals, and mixins to standard CSS. The tool also supports minification, linting, RTL flipping, and CSS class renaming.

The newest version!
/*
 * Copyright 2008 Google Inc.
 *
 * 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 com.google.common.css.compiler.ast;

import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.UnmodifiableIterator;
import com.google.common.css.SourceCodeLocation;

import java.util.Iterator;
import java.util.List;

import javax.annotation.Nullable;

/**
 * A node of the abstract syntax tree.
 *
 * TODO(oana): Declare this class as:
 * public abstract class CssNode {...}
 *
 */
public abstract class CssNode {
  /** The parent of this node. */
  private CssNode parent;
  /** The source code corresponding to this node. */
  private SourceCodeLocation sourceCodeLocation;
  /** List of comments/annotations. */
  private List comments;
  /** Annotation of a node to show whether it should be flipped. */
  private boolean shouldBeFlipped = true;

  /**
   * Constructor of a node.
   */
  public CssNode() {
    this(null, null);
  }

  /**
   * Constructor of a node.
   *
   * @param sourceCodeLocation
   */
  public CssNode(@Nullable SourceCodeLocation sourceCodeLocation) {
    this(null, sourceCodeLocation);
  }

  /**
   * Constructor of a node.
   *
   * @param parent
   */
  public CssNode(@Nullable CssNode parent) {
    this(parent, null);
  }

  /**
   * Constructor of a node.
   *
   * @param parent
   * @param sourceCodeLocation
   */
  public CssNode(@Nullable CssNode parent,
          @Nullable SourceCodeLocation sourceCodeLocation) {
    this(parent, null, sourceCodeLocation);
  }

  /**
   * Constructor of a node.
   *
   * @param parent
   * @param comments
   * @param sourceCodeLocation
   */
  public CssNode(@Nullable CssNode parent,
          @Nullable List comments,
          @Nullable SourceCodeLocation sourceCodeLocation) {
    this.parent = parent;
    this.sourceCodeLocation = sourceCodeLocation;
    if (comments == null) {
      this.comments = Lists.newArrayListWithExpectedSize(0);
    } else {
      this.comments = Lists.newArrayList(comments);
    }
    becomeParentForNodes(this.comments);
  }

  // TODO(oana): Declare this method as public abstract T deepCopy() to ensure
  // that the return type is always correct.
  public abstract CssNode deepCopy();

  public CssNode getParent() {
    return parent;
  }

  void setParent(CssNode parent) {
    this.parent = parent;
  }

  public SourceCodeLocation getSourceCodeLocation() {
    return sourceCodeLocation;
  }

  public void setSourceCodeLocation(
      @Nullable SourceCodeLocation sourceCodeLocation) {
    this.sourceCodeLocation = sourceCodeLocation;
  }

  /**
   * Removes the relation between this node and its parent.
   */
  void removeParent() {
    this.parent = null;
  }

  /**
   * Removes the parent-child relation between this node and a child.
   *
   * @param child
   */
  void removeAsParentOfNode(CssNode child) {
    if (child == null) {
      return;
    }
    Preconditions.checkArgument(child.getParent() == this);
    child.removeParent();
  }

  /**
   * Removes the parent-children relations between this node and a list of
   * children.
   *
   * @param children
   */
  void removeAsParentOfNodes(List children) {
    if (children == null) {
      return;
    }
    for (CssNode child : children) {
      removeAsParentOfNode(child);
    }
  }

  /**
   * Makes this node the parent of a child.
   *
   * @param child
   */
  final void becomeParentForNode(@Nullable CssNode child) {
    if (child == null) {
      return;
    }
    child.setParent(this);
  }

  /**
   * Makes this node the parent of a list of children.
   *
   * @param children
   */
  final void becomeParentForNodes(List children) {
    Preconditions.checkNotNull(children);
    if (children.size() == 0) {
      // otherwise we'll spend a lot of CPU collecting garbage due to
      // the empty iterators we use below (as of June 2012, javac
      // does not optimize the Collection case of enh-for).
      return;
    }
    for (CssNode child : children) {
      becomeParentForNode(child);
    }
  }

  public void appendComment(CssCommentNode comment) {
    comments.add(comment);
    becomeParentForNode(comment);
  }

  public void setComments(List comments) {
    Preconditions.checkNotNull(this.comments);
    removeAsParentOfNodes(this.comments);
    this.comments = Lists.newArrayList(comments);
    becomeParentForNodes(this.comments);
  }

  public List getComments() {
    return comments;
  }

  /**
   * Returns whether one of the comments attached to this node exactly matches
   * the given string.
   */
  public boolean hasComment(String comment) {
    for (CssCommentNode c : comments) {
      if (c.getValue().equals(comment)) {
        return true;
      }
    }
    return false;
  }

  public boolean getShouldBeFlipped() {
    return shouldBeFlipped;
  }

  /**
   * Marks a node whether it should be flipped or not.
   *
   * @param shouldBeFlipped Whether the node should be flipped or not.
   */
  public void setShouldBeFlipped(boolean shouldBeFlipped) {
    this.shouldBeFlipped = shouldBeFlipped;
  }

   List copyToList(List list) {
    return Lists.newArrayList(list);
  }

  /**
   * This is the default implementation of {@code equals()}. The method is
   * marked {@code final} so that nobody changes the default behavior.
   *
   * 

The rationale for not allowing redefinition of equals is that different * compiler passes and different optimizations have their own notion of * equality. In order to avoid confusion and errors everybody that needs a * custom definition of equality and custom hash codes should use customized * collections with custom comparators or hash code providers. * *

In addition, this class should not implement {@link Comparable}. Use * {@link java.util.Comparator} instead. * * @see Object#equals(Object) */ @Override public final boolean equals(@Nullable Object obj) { return super.equals(obj); } /** * This is the default implementation of {@code hashCode()}. The method is * marked {@code final} so that nobody changes the default behavior. * * @see #equals(Object) * @see Object#hashCode() */ @Override public final int hashCode() { return super.hashCode(); } /** * This is the default implementation of {@code toString()}. * *

Overriding this method should only be done for debugging or logging * purposes, not for the actual functionality of the compiler. If a string * representation of a tree is needed, define a Visitor that builds the * desired representation. * * @see Object#toString() */ @Override public String toString() { return super.toString(); } /** * This node and the transitive closure of its {@link #parent}s. */ public Iterable ancestors() { return new Iterable() { public Iterator iterator() { return new UnmodifiableIterator() { private CssNode current = CssNode.this; @Override public boolean hasNext() { return current != null; } @Override public CssNode next() { CssNode result = current; current = current.getParent(); return result; } }; } }; } /** * Returns true when any of a {@code node}'s {@link #ancestors} is a function * node. */ public boolean inFunArgs() { for (CssNode n : ancestors()) { if (n instanceof CssFunctionNode) { return true; } } return false; } public VisitController getVisitController() { return new DefaultVisitController(this, false /* allowMutating */); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy