Package com.google.template.soy.parsepasses

Source Code of com.google.template.soy.parsepasses.RewriteRemainderNodesVisitor

/*
* Copyright 2011 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.template.soy.parsepasses;

import com.google.template.soy.exprtree.ExprRootNode;
import com.google.template.soy.exprtree.FunctionNode;
import com.google.template.soy.soytree.AbstractSoyNodeVisitor;
import com.google.template.soy.soytree.MsgPluralNode;
import com.google.template.soy.soytree.PrintNode;
import com.google.template.soy.soytree.SoyNode;
import com.google.template.soy.soytree.SoyNode.ParentSoyNode;
import com.google.template.soy.soytree.SoySyntaxExceptionUtils;


/**
* Visitor for finding 'print' nodes that are actually 'remainder' nodes, and replacing them with
* the appropriate expression.
*
* <p> Important: Do not use outside of Soy code (treat as superpackage-private).
*
* <p> Important: This pass does not create any MsgPluralRemainderNodes. Instead, we simply
* rewrite the PrintNodes to have the correct computation (subtract constant offset). This class is
* to be used instead of InjectRemainderNodesVisitor.
*
* <p> {@link #exec} should be called on a full parse tree. There is no return value.
*
* @author Mohamed Eldawy
* @author Kai Huang
*/
public class RewriteRemainderNodesVisitor extends AbstractSoyNodeVisitor<Void> {


  /** The MsgPluralNode most recently visited. */
  private MsgPluralNode currPluralNode;


  // -----------------------------------------------------------------------------------------------
  // Implementations for specific nodes.


  @Override protected void visitPrintNode(PrintNode node) {

    ExprRootNode<?> exprRootNode = node.getExprUnion().getExpr();
    if (exprRootNode == null) {
      return;
    }

    // Check for the function node with the function "remainder()".
    if (exprRootNode.getChild(0) instanceof FunctionNode) {
      FunctionNode functionNode = (FunctionNode) exprRootNode.getChild(0);
      if (functionNode.getFunctionName().equals("remainder")) {

        if (currPluralNode == null) {
          // 'remainder' outside 'plural'. Bad!
          throw SoySyntaxExceptionUtils.createWithNode(
              "The special function 'remainder' is for use in plural messages" +
                  " (tag " + node.toSourceString() + ").",
              node);
        }
        // 'remainder' with no parameters or more than one parameter. Bad!
        if (functionNode.numChildren() != 1) {
          throw SoySyntaxExceptionUtils.createWithNode(
              "The function 'remainder' has to have exactly one argument" +
                  " (tag " + node.toSourceString() + ").",
              node);
        }
        // 'remainder' with a different expression than the enclosing 'plural'. Bad!
        if (! functionNode.getChild(0).toSourceString().equals(
                  currPluralNode.getExpr().toSourceString())) {
          throw SoySyntaxExceptionUtils.createWithNode(
              "The parameter to 'remainder' has to be the same as the 'plural' variable" +
                  " (tag " + node.toSourceString() + ").",
              node);
        }
        // 'remainder' with a 0 offset. Bad!
        if (currPluralNode.getOffset() == 0) {
          throw SoySyntaxExceptionUtils.createWithNode(
              "In 'plural' block, use of 'remainder' function is unnecessary since offset = 0" +
                  " (tag " + node.toSourceString() + ").",
              node);
        }
        // 'remainder' with 'phname' attribute. Bad!
        if (node.getUserSuppliedPlaceholderName() != null) {
          throw SoySyntaxExceptionUtils.createWithNode(
              "Cannot use special function 'remainder' and attribute 'phname' together" +
                  " (tag " + node.toSourceString() + ").",
              node);
        }

        // Now rewrite the PrintNode (reusing the old node id).
        String newExprText =
            "(" + currPluralNode.getExpr().toSourceString() + ") - " + currPluralNode.getOffset();
        PrintNode newPrintNode = new PrintNode(node.getId(), node.isImplicit(), newExprText, null);
        newPrintNode.addChildren(node.getChildren());
        node.getParent().replaceChild(node, newPrintNode);
      }
    }
  }


  @Override protected void visitMsgPluralNode(MsgPluralNode node) {
    currPluralNode = node;
    visitChildren(node);
    currPluralNode = null;
  }


  // -----------------------------------------------------------------------------------------------
  // Fallback implementation.


  @Override protected void visitSoyNode(SoyNode node) {
    if (node instanceof ParentSoyNode<?>) {
      visitChildrenAllowingConcurrentModification((ParentSoyNode<?>) node);
    }
  }

}
TOP

Related Classes of com.google.template.soy.parsepasses.RewriteRemainderNodesVisitor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.