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

com.google.common.css.compiler.passes.ResolveCustomFunctionNodes 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: 1.8.0
Show newest version
/*
 * Copyright 2009 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.passes;

import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableSet;
import com.google.common.css.compiler.ast.*;

import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * This compiler pass replaces {@link CssCustomFunctionNode} instances with the
 * list of nodes returned by the GssFunction.
 */
public class ResolveCustomFunctionNodes extends DefaultTreeVisitor
        implements CssCompilerPass {

    private final MutatingVisitController visitController;
    protected final Map functionMap;
    private final ErrorManager errorManager;
    private final boolean allowUnknownFunctions;
    private final Set allowedNonStandardFunctions;

    /**
     * Constructs the pass.
     *
     * @param visitController The visit controller
     * @param errorManager    The error manager
     * @param functionMap     The map from function names to resolve to GSS functions
     */
    public ResolveCustomFunctionNodes(MutatingVisitController visitController,
                                      ErrorManager errorManager,
                                      Map functionMap) {
        this(visitController, errorManager, functionMap,
                false /* allowUnknownFunctions */);
    }

    /**
     * Constructs the pass.
     *
     * @param visitController       The visit controller
     * @param errorManager          The error manager
     * @param functionMap           The map from function names to resolve to GSS functions
     * @param allowUnknownFunctions Whether to allow unknown function calls,
     *                              leaving them as is, instead of reporting an error
     */
    public ResolveCustomFunctionNodes(MutatingVisitController visitController,
                                      ErrorManager errorManager,
                                      Map functionMap,
                                      boolean allowUnknownFunctions) {
        this(visitController, errorManager, functionMap, allowUnknownFunctions,
                ImmutableSet.of() /* allowedNonStandardFunctions */);
    }

    /**
     * Constructs the pass.
     *
     * @param visitController             The visit controller
     * @param errorManager                The error manager
     * @param functionMap                 The map from function names to resolve to GSS functions
     * @param allowUnknownFunctions       Whether to allow unknown function calls,
     *                                    leaving them as is, instead of reporting an error
     * @param allowedNonStandardFunctions functions that should not yield a
     *                                    warning if they appear in a stylesheet
     */
    public ResolveCustomFunctionNodes(MutatingVisitController visitController,
                                      ErrorManager errorManager,
                                      Map functionMap,
                                      boolean allowUnknownFunctions,
                                      Set allowedNonStandardFunctions) {
        Preconditions.checkNotNull(functionMap);
        this.visitController = visitController;
        this.errorManager = errorManager;
        this.functionMap = functionMap;
        this.allowUnknownFunctions = allowUnknownFunctions;
        this.allowedNonStandardFunctions = ImmutableSet.copyOf(
                allowedNonStandardFunctions);
    }

    @Override
    public void leaveFunctionNode(CssFunctionNode functionNode) {
        if (!(functionNode instanceof Proxiable)) {
            return;
        }

        CssCustomFunctionNode node = (CssCustomFunctionNode) functionNode;

        List functionResult = node.getResult();
        if (functionResult == null) {
            // Look up the function's name in the map.
            String functionName = node.getFunctionName();
            GssFunction function = functionMap.get(functionName);
            if (function == null) {
                if (!allowUnknownFunctions && !allowedNonStandardFunctions.contains(
                        functionName)) {
                    errorManager.report(new GssError(
                            String.format("Unknown function \"%s\"", functionName),
                            node.getSourceCodeLocation()));
                    visitController.removeCurrentNode();
                }
                return;
            }
            List arguments =
                    CssCustomFunctionNode.fixupFunctionArguments(node.getArguments().childIterable());

            Integer expArgNumber = function.getNumExpectedArguments();
            int argNumber = arguments.size();
            if (expArgNumber != null && expArgNumber != argNumber) {
                errorManager.report(new GssError("Function expects " + expArgNumber
                        + " arguments but has " + argNumber,
                        node.getSourceCodeLocation()));
                visitController.removeCurrentNode();
                return;
            }

            try {
                functionResult = evaluateFunction(node, function, arguments, errorManager);
            } catch (GssFunctionException e) {
                visitController.removeCurrentNode();
                return;
            } catch (RuntimeException e) {
                errorManager.report(
                        new GssError(
                                Throwables.getStackTraceAsString(e),
                                node.getSourceCodeLocation()));
                visitController.removeCurrentNode();
                return;
            }
        }
        visitController.replaceCurrentBlockChildWith(functionResult, false);
    }

    /**
     * Evaluates the given function node.
     *
     * 

Subclasses may sublcass this method to change the evaluation * process in some circumstances. * * @param node the function node to evaluate * @param function the GSS function matching this node * @param arguments the arguments of this node * @param errorManager the error manager passed into the GSS function call * @return the result of the evaluation as a list of value nodes * @throws GssFunctionException if the function call is invalid * @throws RuntimeException if the function call fails to complete */ protected List evaluateFunction( CssCustomFunctionNode node, GssFunction function, List arguments, ErrorManager errorManager) throws GssFunctionException { List functionResult = function.getCallResultNodes(arguments, errorManager); node.setResult(functionResult); return functionResult; } @Override public void runPass() { visitController.startVisit(this); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy