com.google.common.css.compiler.ast.CssCustomFunctionNode Maven / Gradle / Ivy
Show all versions of closure-stylesheets Show documentation
/*
* 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.collect.Lists;
import com.google.common.css.SourceCodeLocation;
import java.util.List;
import javax.annotation.Nullable;
/**
* A node representing a custom GSS function call.
*
* @author [email protected] (Oana Florescu)
* @author [email protected] (Damian Gajda)
*/
public class CssCustomFunctionNode extends CssFunctionNode
implements Proxiable {
private final String gssFunctionName;
protected List resultNodes;
/**
* Constructor of the node.
*
* @param gssFunctionName name of the function "called" by this node
* @param sourceCodeLocation location of this node
*/
public CssCustomFunctionNode(
String gssFunctionName,
SourceCodeLocation sourceCodeLocation) {
super(Function.CUSTOM, sourceCodeLocation);
this.gssFunctionName = gssFunctionName;
}
/**
* Copy constructor.
*
* @param function the copied custom function node
*/
public CssCustomFunctionNode(CssCustomFunctionNode function) {
super(function);
this.gssFunctionName = function.getFunctionName();
}
/**
* Constructor used by the proxy mechanism, which avoids creation of child
* nodes.
*
* NOTE(dgajda): The signature of this constructor only differs in argument
* order from the main constructor of this class.
*
* @param gssFunctionName name of the function "called" by this node
* @param sourceCodeLocation location of this node
*/
private CssCustomFunctionNode(
@Nullable SourceCodeLocation sourceCodeLocation,
String gssFunctionName) {
super(sourceCodeLocation, Function.CUSTOM);
this.gssFunctionName = gssFunctionName;
}
@Override
public CssCustomFunctionNode deepCopy() {
return new CssCustomFunctionNode(this);
}
@Override
public String getFunctionName() {
return gssFunctionName;
}
@Override
public String toString() {
return gssFunctionName + super.toString();
}
/** {@inheritDoc} */
@Override
public void setArguments(CssFunctionArgumentsNode arguments) {
resultNodes = null;
super.setArguments(arguments);
}
/**
* @return the copy-on-write proxy for this node
*/
@Override
public CssCustomFunctionNode createProxy() {
return new CssCustomFunctionNodeProxy(this);
}
/**
* @return cached result of function value computation
*/
public List getResult() {
return resultNodes;
}
/**
* Saves the value of function computation for later use.
*
* @param functionResult the list of nodes returned by the call to the
* {@link GssFunction}
*/
public void setResult(List functionResult) {
resultNodes = functionResult;
}
/**
* Copy-on-Write proxy for {@link CssCustomFunctionNode} used to avoid copying
* of function call subtrees in
* {@link com.google.common.css.compiler.passes.ReplaceConstantReferences}
* pass. It behaves as a proxy of the original node until a write operation
* happens. When the first write operation happens, proxy node copies the
* original node and since then acts as a plain {@link CssCustomFunctionNode}.
*
* NOTE(dgajda): Proxied custom function nodes are also replaced by proxies
* of themselves to disallow changes, which would be visible to all proxy
* nodes. Only one kind of changes is propagated to proxy nodes - this is
* setting of function computation results.
*/
public static class CssCustomFunctionNodeProxy extends CssCustomFunctionNode {
private CssCustomFunctionNode proxiedNode;
/**
* Constructs the node proxy. It uses a special super class constructor
* which avoids unnecessary initialization of arguments node.
*
* @param function the proxied node
*/
public CssCustomFunctionNodeProxy(CssCustomFunctionNode function) {
super(function.getSourceCodeLocation(),
function.getFunctionName());
this.proxiedNode = function;
setChunk(function.getChunk());
}
/** {@inheritDoc} */
@Override
public CssFunctionArgumentsNode getArguments() {
return proxiedNode != null ?
proxiedNode.getArguments() : super.getArguments();
}
/** {@inheritDoc} */
@Override
public void setArguments(CssFunctionArgumentsNode arguments) {
proxiedNode = null;
super.setArguments(arguments);
}
/** {@inheritDoc} */
@Override
public CssCustomFunctionNode createProxy() {
CssCustomFunctionNode newProxiedNode = proxiedNode != null ?
proxiedNode : this;
return new CssCustomFunctionNodeProxy(newProxiedNode);
}
/** {@inheritDoc} */
@Override
public List getResult() {
if (proxiedNode == null) {
return super.getResult();
}
List proxiedNodeResults = proxiedNode.getResult();
if (proxiedNodeResults == null) {
return null;
}
// Copy results because they are not owned by this node.
List result =
Lists.newArrayListWithCapacity(proxiedNodeResults.size());
for (CssValueNode cssValueNode : proxiedNodeResults) {
result.add(cssValueNode.deepCopy());
}
return result;
}
/**
* Sets the results of function computation for this node, can set results
* on the proxied node. This is harmless because proxied node is exactly
* the same as proxy node, and function computation results are a
* derivative of function arguments.
*/
@Override
public void setResult(List functionResult) {
if (proxiedNode == null) {
super.setResult(functionResult);
} else {
proxiedNode.setResult(functionResult);
}
}
}
}