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

com.google.common.css.compiler.ast.CssBooleanExpressionNode 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.

There is a newer version: 20160212
Show 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.css.SourceCodeLocation;

import javax.annotation.Nullable;

/**
 * A node representing a boolean expression to evaluate.
 *
 */
// TODO(user): It might be better for each operator to have a list of
//     operands, not just the left and right operand. Thus, A || B || C would be
//     represented as a single operator node and a list of three constant nodes
//     (similar to what the old tree structure does, but with explicit lists).
//     This might make the code larger but has the potential of faster
//     compilation (important for Gmail). This structure might also ease
//     constructing a canonical form of the expression and simplifying
//     expressions (such as EXPR || !EXPR).
public class CssBooleanExpressionNode extends CssValueNode {
  /**
   * Boolean expression node types. The types are given in the order of their
   * precedence, "!" having the highest priority.
   */
  public enum Type {
    CONSTANT(null),
    NOT("!"),
    AND("&&"),
    OR("||");

    public static final String TRUE_CONSTANT = "TRUE";
    public static final String FALSE_CONSTANT = "FALSE";

    private final String operatorString;

    private Type(@Nullable String operatorString) {
      this.operatorString = operatorString;
    }

    public String getOperatorString() {
      return operatorString;
    }

    public boolean isConstant() {
      return this == CONSTANT;
    }

    public boolean isOperator() {
      return !isConstant();
    }

    public boolean isBinaryOperator() {
      Preconditions.checkArgument(this.isOperator());
      return this != NOT;
    }

    public boolean isUnaryOperator() {
      Preconditions.checkArgument(this.isOperator());
      return this == NOT;
    }

    /**
     * Lower numbers are lower priority.
     */
    public int getPriority() {
      return -this.ordinal();
    }
    /**
     * For debugging only.
     */
    @Override
    public String toString() {
      return getOperatorString();
    }
  }

  private final Type type;
  private final CssBooleanExpressionNode left;
  private final CssBooleanExpressionNode right;

  /**
   * Constructor for a boolean expression node.
   *
   * @param type Type of node
   * @param value Value of node
   * @param left Left expression node
   * @param right Right expression node
   * @param sourceCodeLocation The location of the source code
   */
  public CssBooleanExpressionNode(Type type, String value,
      @Nullable CssBooleanExpressionNode left,
      @Nullable CssBooleanExpressionNode right,
      @Nullable SourceCodeLocation sourceCodeLocation) {
    super(value, sourceCodeLocation);
    this.type = type;
    this.left = left;
    this.right = right;
    becomeParentForNode(this.left);
    becomeParentForNode(this.right);
    Preconditions.checkArgument(isValidExpressionTree());
  }

  /**
   * Constructor for a boolean expression node.
   *
   * @param type Type of node
   * @param value Value of node
   * @param left Left expression node
   * @param sourceCodeLocation The location of the source code
   */
  // TODO(oana): Maybe we want to change the constructor to build the right
  // child instead of the left ona for the unary operators.
  public CssBooleanExpressionNode(Type type, String value,
      @Nullable CssBooleanExpressionNode left,
      @Nullable SourceCodeLocation sourceCodeLocation) {
    this(type, value, left, null, sourceCodeLocation);
  }

  /**
   * Constructor for a boolean expression node.
   *
   * @param type
   * @param value
   * @param sourceCodeLocation
   */
  public CssBooleanExpressionNode(Type type, String value,
      @Nullable SourceCodeLocation sourceCodeLocation) {
    this(type, value, null, null, sourceCodeLocation);
  }

  /**
   * Constructor for a boolean expression node.
   *
   * @param type Type of node
   * @param value Value of node
   */
  public CssBooleanExpressionNode(Type type, String value) {
    this(type, value, null, null, null);
  }

  /**
   * Copy constructor.
   */
  public CssBooleanExpressionNode(CssBooleanExpressionNode node) {
    super(node);
    this.type = node.getType();
    if (node.getLeft() != null) {
      this.left = new CssBooleanExpressionNode(node.getLeft());
      becomeParentForNode(this.left);
    } else {
      this.left = null;
    }
    if (node.getRight() != null) {
      this.right = new CssBooleanExpressionNode(node.getRight());
      becomeParentForNode(this.right);
    } else {
      this.right = null;
    }
  }

  @Override
  public CssBooleanExpressionNode deepCopy() {
    return new CssBooleanExpressionNode(this);
  }

  public Type getType() {
    return type;
  }

  public CssBooleanExpressionNode getLeft() {
    return left;
  }

  public CssBooleanExpressionNode getRight() {
    return right;
  }

  /**
   * Checks if the expression tree is valid.
   */
  public boolean isValidExpressionTree() {
    if (getType().isConstant()) {
      return true;
    } else if (!getType().isOperator()) {
      return getLeft() == null && getRight() == null;
    } else if (getType().isBinaryOperator()) {
      return getLeft() != null && getRight() != null;
    } else if (getType().isUnaryOperator()) {
      return getLeft() != null && getRight() == null;
    } else {
      // assert false
      return false;
    }
  }

  /**
   * For debugging only.
   */
  private void appendChildExpression(StringBuilder sb,
      CssBooleanExpressionNode child) {
    if (child.getType().getPriority() >= getType().getPriority()) {
      sb.append(child.toString());
    } else {
      sb.append("(" + child.toString() + ")");
    }
  }

  /**
   * For debugging only.
   */
  @Override
  public String toString() {
    if (!getType().isOperator()) {
      return getValue();
    } else if (getType().isBinaryOperator()) {
      StringBuilder sb = new StringBuilder();
      appendChildExpression(sb, getLeft());
      sb.append(" " + this.getType().getOperatorString() + " ");
      appendChildExpression(sb, getRight());
      return sb.toString();
    } else if (getType().isUnaryOperator()) {
      StringBuilder sb = new StringBuilder();
      sb.append(this.getType().getOperatorString());
      appendChildExpression(sb, getLeft());
      return sb.toString();
    } else {
      // assert false;
      return null;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy