Visits this node, then visits its element expressions in order.
Any empty elements are represented by {@link EmptyExpression}
objects, so the callback will never be passed {@code null}.
348842
@Override
    public void visit(NodeVisitor v) {
        if (v.visit(this)) {
            for (AstNode e : getElements()) {
                e.visit(v);
            }
        }
    }
260694
public static void ensureXPathNotEmpty(NodeList nodeList, String expression) {
    if (nodeList == null || nodeList.getLength() == 0) {
      throw LOG.unableToFindXPathExpression(expression);
    }
  }
707586
public T visitList(List elm, C context) {
        if (elm.getTypeSpecifier() != null) {
            visitElement(elm.getTypeSpecifier(), context);
        }
        for (Expression element : elm.getElement()) {
            visitElement(element, context);
        }
        return null;
    }
213173
private void visitGetElem(Node n) {
    validator.expectIndexMatch(n, getJSType(n.getFirstChild()), getJSType(n.getLastChild()));
    ensureTyped(n);
  }
852677
public boolean isEmpty() {
        boolean empty = true;
        boolean done = false;
        while (empty && !done) {
            for (ConcurrentServiceReferenceSet<V> s : elementMap.values()) {
                empty &= s.isEmpty();
            }
            done = true;
        }
        return empty;
    }
1060748
private void evaluateExpressions() throws JspException {
        /* 
         * Note: we don't check for type mismatches here; we assume
         * the expression evaluator will return the expected type
         * (by virtue of knowledge we give it about what that type is).
         * A ClassCastException here is truly unexpected, so we let it
         * propagate up.
         */

        if (begin_ != null) {
            Object r = ExpressionEvaluatorManager.evaluate(
                    "begin", begin_, Integer.class, this, pageContext);
            if (r == null) {
                throw new NullAttributeException("forEach", "begin");
            }
            begin = ((Integer) r).intValue();
            validateBegin();
        }

        if (end_ != null) {
            Object r = ExpressionEvaluatorManager.evaluate(
                    "end", end_, Integer.class, this, pageContext);
            if (r == null) {
                throw new NullAttributeException("forEach", "end");
            }
            end = ((Integer) r).intValue();
            validateEnd();
        }

        if (step_ != null) {
            Object r = ExpressionEvaluatorManager.evaluate(
                    "step", step_, Integer.class, this, pageContext);
            if (r == null) {
                throw new NullAttributeException("forEach", "step");
            }
            step = ((Integer) r).intValue();
            validateStep();
        }

        if (items_ != null) {
            rawItems = ExpressionEvaluatorManager.evaluate(
                    "items", items_, Object.class, this, pageContext);
            // use an empty list to indicate "no iteration", if relevant
            if (rawItems == null) {
                rawItems = new ArrayList();
            }
        }
    }
168281
private @Nonnull NodeList evaluate(String xpath) {
        try {
            XPathExpression expr = xpf.newXPath().compile(xpath);
            return (NodeList) expr.evaluate(node, XPathConstants.NODESET);
        } catch (XPathExpressionException ex) {
            throw new IllegalArgumentException("Invalid XPath '" + xpath + "'", ex);
        }
    }
145942
private void evaluateExpressions() throws JspException {
        /* 
         * Note: we don't check for type mismatches here; we assume
         * the expression evaluator will return the expected type
         * (by virtue of knowledge we give it about what that type is).
         * A ClassCastException here is truly unexpected, so we let it
         * propagate up.
         */

        if (value_ != null) {
            value = ExpressionEvaluatorManager.evaluate(
                    "value", value_, Object.class, this, pageContext);
        }
    }
65507
@Override
    public void visit(NodeVisitor v) {
        if (v.visit(this)) {
            initializer.visit(v);
            condition.visit(v);
            increment.visit(v);
            body.visit(v);
        }
    }
723493
@Override
    public void visit(NodeVisitor v) {
        if (v.visit(this)) {
            target.visit(v);
            if (initializer != null) {
                initializer.visit(v);
            }
        }
    }
477956
private void evaluateExpressions() throws JspException {
        /* 
         * Note: we don't check for type mismatches here; we assume
         * the expression evaluator will return the expected type
         * (by virtue of knowledge we give it about what that type is).
         * A ClassCastException here is truly unexpected, so we let it
         * propagate up.
         */

        if (escapeXml_ != null) {
            Boolean b = (Boolean) ExpressionUtil.evalNotNull(
                    "out",
                    "escapeXml",
                    escapeXml_,
                    Boolean.class,
                    this,
                    pageContext);
            if (b == null) {
                escapeXml = false;
            } else {
                escapeXml = b.booleanValue();
            }
        }
    }
1206416
@Override
    public void visit(Node node) throws ELException {
        if (node instanceof AstFunction) {

            AstFunction funcNode = (AstFunction) node;

            Method m = null;

            if (this.fnMapper != null) {
                m = fnMapper.resolveFunction(funcNode.getPrefix(), funcNode
                        .getLocalName());
            }

            // References to variables that refer to lambda expressions will be
            // parsed as functions. This is handled at runtime but at this point
            // need to treat it as a variable rather than a function.
            if (m == null && this.varMapper != null &&
                    funcNode.getPrefix().length() == 0) {
                this.varMapper.resolveVariable(funcNode.getLocalName());
                return;
            }

            if (this.fnMapper == null) {
                throw new ELException(MessageFactory.get("error.fnMapper.null"));
            }

            if (m == null) {
                throw new ELException(MessageFactory.get(
                        "error.fnMapper.method", funcNode.getOutputName()));
            }

            int methodParameterCount = m.getParameterTypes().length;
            // AstFunction->MethodParameters->Parameters()
            int inputParameterCount = node.jjtGetChild(0).jjtGetNumChildren();
            if (m.isVarArgs() && inputParameterCount < methodParameterCount - 1 ||
                    !m.isVarArgs() && inputParameterCount != methodParameterCount) {
                throw new ELException(MessageFactory.get(
                        "error.fnMapper.paramcount", funcNode.getOutputName(),
                        "" + methodParameterCount, "" + node.jjtGetChild(0).jjtGetNumChildren()));
            }
        } else if (node instanceof AstIdentifier && this.varMapper != null) {
            String variable = ((AstIdentifier) node).getImage();

            // simply capture it
            this.varMapper.resolveVariable(variable);
        }
    }
1018705
@Override protected void visitIfNode(IfNode node) {

    // Create another instance of this visitor class for generating JS expressions from children.
    GenJsExprsVisitor genJsExprsVisitor =
        genJsExprsVisitorFactory.create(translationContext, templateAliases, errorReporter);
    CodeChunk.Generator generator = translationContext.codeGenerator();

    List<Expression> ifs = new ArrayList<>();
    List<Expression> thens = new ArrayList<>();
    Expression trailingElse = null;

    for (SoyNode child : node.getChildren()) {

      if (child instanceof IfCondNode) {
        IfCondNode ifCond = (IfCondNode) child;

        ifs.add(translateExpr(ifCond.getExpr()));
        thens.add(CodeChunkUtils.concatChunks(genJsExprsVisitor.exec(ifCond)));
      } else if (child instanceof IfElseNode) {
        trailingElse = CodeChunkUtils.concatChunks(genJsExprsVisitor.exec(child));
      } else {
        throw new AssertionError();
      }
    }

    Preconditions.checkState(ifs.size() == thens.size());

    ConditionalExpressionBuilder builder = Expression.ifExpression(ifs.get(0), thens.get(0));

    for (int i = 1; i < ifs.size(); i++) {
      builder.addElseIf(ifs.get(i), thens.get(i));
    }

    Expression ifChunk =
        trailingElse != null
            ? builder.setElse(trailingElse).build(generator)
            : builder.setElse(LITERAL_EMPTY_STRING).build(generator);

    chunks.add(ifChunk);
  }
1136725
@Override
  protected void visitForNode(ForNode node) {
    boolean hasIfempty = (node.numChildren() == 2);
    // NOTE: below we call id(varName) on a number of variables instead of using
    // VariableDeclaration.ref(),  this is because the refs() might be referenced on the other side
    // of a call to visitChildrenReturningCodeChunk.
    // That will break the normal behavior of FormattingContext being able to tell whether or not an
    // initial statement has already been generated because it eagerly coerces the value to a
    // string.  This will lead to redundant variable declarations.
    // When visitChildrenReturningCodeChunk is gone, this can be cleaned up, but for now we have to
    // manually decide where to declare the variables.
    List<Statement> statements = new ArrayList<>();
    // Build some local variable names.
    ForNonemptyNode nonEmptyNode = (ForNonemptyNode) node.getChild(0);
    String varPrefix = nonEmptyNode.getVarName() + node.getId();

    // TODO(b/32224284): A more consistent pattern for local variable management.
    String limitName = varPrefix + "ListLen";
    Expression limitInitializer;
    Optional<RangeArgs> args = RangeArgs.createFromNode(node);
    Function<Expression, Expression> getDataItemFunction;
    if (args.isPresent()) {
      RangeArgs range = args.get();
      // if any of the expressions are too expensive, allocate local variables for them
      final Expression start =
          maybeStashInLocal(
              range.start().isPresent() ? translateExpr(range.start().get()) : Expression.number(0),
              varPrefix + "_RangeStart",
              statements);
      final Expression end =
          maybeStashInLocal(translateExpr(range.limit()), varPrefix + "_RangeEnd", statements);
      final Expression step =
          maybeStashInLocal(
              range.increment().isPresent()
                  ? translateExpr(range.increment().get())
                  : Expression.number(1),
              varPrefix + "_RangeStep",
              statements);
      // the logic we want is
      // step * (end-start) < 0 ? 0 : ( (end-start)/step + ((end-start) % step == 0 ? 0 : 1));
      // but given that all javascript numbers are doubles we can simplify this somewhat.
      // Math.max(0, Match.ceil((end - start)/step))
      // should yield identical results.
      limitInitializer =
          dottedIdNoRequire("Math.max")
              .call(
                  number(0), dottedIdNoRequire("Math.ceil").call(end.minus(start).divideBy(step)));
      // optimize for foreach over a range
      getDataItemFunction = index -> start.plus(index.times(step));
    } else {
      // Define list var and list-len var.
      Expression dataRef = translateExpr(node.getExpr());
      final String listVarName = varPrefix + "List";
      Expression listVar = VariableDeclaration.builder(listVarName).setRhs(dataRef).build().ref();
      // does it make sense to store this in a variable?
      limitInitializer = listVar.dotAccess("length");
      getDataItemFunction = index -> id(listVarName).bracketAccess(index);
    }

    // Generate the foreach body as a CodeChunk.
    Expression limit = id(limitName);
    statements.add(VariableDeclaration.builder(limitName).setRhs(limitInitializer).build());
    Statement foreachBody = handleForeachLoop(nonEmptyNode, limit, getDataItemFunction);

    if (hasIfempty) {
      // If there is an ifempty node, wrap the foreach body in an if statement and append the
      // ifempty body as the else clause.
      Statement ifemptyBody = visitChildrenReturningCodeChunk(node.getChild(1));
      Expression limitCheck = limit.op(Operator.GREATER_THAN, number(0));

      foreachBody = ifStatement(limitCheck, foreachBody).setElse(ifemptyBody).build();
    }
    statements.add(foreachBody);
    jsCodeBuilder.append(Statement.of(statements));
  }
1250565
private AbstractExpression parseExpressionNode(VoltXMLElement exprNode) {
        String elementName = exprNode.name.toLowerCase();

        XMLElementExpressionParser parser = m_exprParsers.get(elementName);
        if (parser == null) {
            throw new PlanningErrorException("Unsupported expression node '" + elementName + "'");
        }
        AbstractExpression retval = parser.parse(this, exprNode);
        assert("asterisk".equals(elementName) || retval != null);
        return retval;
    }
370873
@Override
  protected void visitExprNode(ExprNode node) {

    if (!(node instanceof ParentExprNode)) {
      return;
    }
    ParentExprNode nodeAsParent = (ParentExprNode) node;

    // Recurse.
    visitChildren(nodeAsParent);

    // If all children are constants, we attempt to preevaluate this node and replace it with a
    // constant.
    for (ExprNode child : nodeAsParent.getChildren()) {
      if (!isConstant(child)) {
        return; // cannot preevaluate
      }
    }
    attemptPreeval(nodeAsParent);
  }
1063831
public void setExpression(AstNode expression) {
        assertNotNull(expression);
        expr = expression;
        expression.setParent(this);
        setLineno(expression.getLineno());
    }