com.google.common.css.compiler.ast.CssBooleanExpressionNode.java Source code

Java tutorial

Introduction

Here is the source code for com.google.common.css.compiler.ast.CssBooleanExpressionNode.java

Source

/*
 * 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;
        }
    }
}