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

com.google.escapevelocity.ParseNode Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2023 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.escapevelocity;

import com.google.escapevelocity.Template.ResourceOpener;
import java.io.IOException;
import java.util.Map;

/**
 * Representation of a {@code #parse} directive in the parse tree.
 *
 * 

A {@code #parse ()} directive does nothing until the template is evaluated. Then the * {@code } should evaluate to a string, which will be used to derive a nested {@link * Template}. If the string was seen before (in this evaluation, or an earlier evaluation) then the * {@code Template} will be retrieved from the {@code parseCache}. Otherwise we will get a {@link * Reader} from the {@link ResourceOpener} and parse its contents to produce a new {@code Template}, * which we will record in the {@code parseCache}. Either way, we will execute the nested {@code * Template}, which means adding its macros to the {@link EvaluationContext} and evaluating it to * add text to the final output. */ class ParseNode extends Node { private final ExpressionNode nestedResourceNameExpression; private final ResourceOpener resourceOpener; private final Map parseCache; ParseNode( String resourceName, int startLine, ExpressionNode nestedResourceNameExpression, ResourceOpener resourceOpener, Map parseCache) { super(resourceName, startLine); this.nestedResourceNameExpression = nestedResourceNameExpression; this.resourceOpener = resourceOpener; this.parseCache = parseCache; } @Override void render(EvaluationContext context, StringBuilder output) { Object resourceNameObject = nestedResourceNameExpression.evaluate(context); if (!(resourceNameObject instanceof String)) { String what = resourceNameObject == null ? "null" : resourceNameObject.getClass().getName(); throw evaluationException("Argument to #parse must be a string, not " + what); } String resourceName = (String) resourceNameObject; Template template = parseCache.get(resourceName); if (template == null) { try { template = Template.parseFrom(resourceName, resourceOpener, parseCache); parseCache.put(resourceName, template); } catch (ParseException | IOException e) { throw evaluationException(e); } } // Lift macros from the nested template into the evaluation context so we can evaluate the // nested template with the pre-processed macros available. The macros will also be available in // the calling template after the #parse. template.getMacros().forEach((name, macro) -> context.getMacros().putIfAbsent(name, macro)); try { template.render(context, output); } catch (BreakException e) { if (e.forEachScope()) { // this isn't for us throw e; } // OK: the #break has broken out of this #parse } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy