Package com.google.template.soy

Source Code of com.google.template.soy.SoyUtils

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

import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.io.Files;
import com.google.common.io.InputSupplier;
import com.google.template.soy.base.SoySyntaxException;
import com.google.template.soy.data.internalutils.DataUtils;
import com.google.template.soy.data.restricted.FloatData;
import com.google.template.soy.data.restricted.IntegerData;
import com.google.template.soy.data.restricted.PrimitiveData;
import com.google.template.soy.exprparse.ExpressionParser;
import com.google.template.soy.exprparse.ParseException;
import com.google.template.soy.exprparse.TokenMgrError;
import com.google.template.soy.exprtree.DataRefNode;
import com.google.template.soy.exprtree.ExprNode;
import com.google.template.soy.exprtree.ExprNode.PrimitiveNode;
import com.google.template.soy.exprtree.FloatNode;
import com.google.template.soy.exprtree.GlobalNode;
import com.google.template.soy.exprtree.IntegerNode;
import com.google.template.soy.exprtree.OperatorNodes.NegativeOpNode;
import com.google.template.soy.internal.base.Pair;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
* Public utilities for Soy users.
*
* @author Kai Huang
*/
public class SoyUtils {


  private SoyUtils() {}


  /**
   * Generates the text for a compile-time globals file in the format expected by the Soy compiler
   * and appends the generated text to the given {@code Appendable}.
   *
   * <p> The generated lines will follow the iteration order of the provided map.
   *
   * <p> Important: When you write the output to a file, be sure to use UTF-8 encoding.
   *
   * @param compileTimeGlobalsMap Map from compile-time global name to value. The values can be
   *     any of the Soy primitive types: null, boolean, integer, float (Java double), or string.
   * @param output The object to append the generated text to.
   * @throws SoySyntaxException If one of the values is not a valid Soy primitive type.
   * @throws IOException If there is an error appending to the given {@code Appendable}.
   * @see #generateCompileTimeGlobalsFile(Map, File)
   */
  public static void generateCompileTimeGlobalsFile(
      Map<String, ?> compileTimeGlobalsMap, Appendable output) throws IOException {

    Map<String, PrimitiveData> compileTimeGlobals =
        DataUtils.convertCompileTimeGlobalsMap(compileTimeGlobalsMap);

    for (Map.Entry<String, PrimitiveData> entry : compileTimeGlobals.entrySet()) {
      String valueSrcStr = DataUtils.convertPrimitiveDataToExpr(entry.getValue()).toSourceString();
      output.append(entry.getKey()).append(" = ").append(valueSrcStr).append("\n");
    }
  }


  /**
   * Generates a compile-time globals file in the format expected by the Soy compiler.
   *
   * <p> The generated lines will follow the iteration order of the provided map.
   *
   * @param compileTimeGlobalsMap Map from compile-time global name to value. The values can be
   *     any of the Soy primitive types: null, boolean, integer, float (Java double), or string.
   * @param file The file to write the generated text to.
   * @throws SoySyntaxException If one of the values is not a valid Soy primitive type.
   * @throws IOException If there is an error appending to the given {@code Appendable}.
   * @see #generateCompileTimeGlobalsFile(Map, Appendable)
   */
  public static void generateCompileTimeGlobalsFile(
      Map<String, ?> compileTimeGlobalsMap, File file) throws IOException {

    BufferedWriter writer = Files.newWriter(file, Charsets.UTF_8);
    generateCompileTimeGlobalsFile(compileTimeGlobalsMap, writer);
    writer.close();
  }


  /**
   * Error types for bad lines in the compile-time globals file.
   */
  private static enum CompileTimeGlobalsFileError {

    INVALID_FORMAT("Invalid line format"),
    INVALID_VALUE("Invalid value"),
    NON_PRIMITIVE_VALUE("Non-primitive value");

    private final String errorString;

    private CompileTimeGlobalsFileError(String errorString) {
      this.errorString = errorString;
    }

    @Override public String toString() {
      return errorString;
    }
  }


  /** Pattern for one line in the compile-time globals file. */
  // Note: group 1 = key, group 2 = value.
  private static final Pattern COMPILE_TIME_GLOBAL_LINE =
      Pattern.compile("([a-zA-Z_][a-zA-Z_0-9.]*) \\s* = \\s* (.+)", Pattern.COMMENTS);


  /**
   * Parses a globals file in the format created by {@link #generateCompileTimeGlobalsFile} into a
   * map from global name to primitive value.
   * @param inputSupplier A supplier that returns a reader for the globals file.
   * @return The parsed globals map.
   * @throws IOException If an error occurs while reading the globals file.
   * @throws SoySyntaxException If the globals file is not in the correct format.
   */
  public static ImmutableMap<String, PrimitiveData> parseCompileTimeGlobals(
      InputSupplier<? extends Reader> inputSupplier) throws IOException, SoySyntaxException {
    ImmutableMap.Builder<String, PrimitiveData> compileTimeGlobalsBuilder = ImmutableMap.builder();
    List<Pair<CompileTimeGlobalsFileError, String>> errors = Lists.newArrayListWithCapacity(0);

    BufferedReader reader = new BufferedReader(inputSupplier.getInput());
    for (String line = reader.readLine(); line != null; line = reader.readLine()) {

      if (line.startsWith("//") || line.trim().length() == 0) {
        continue;
      }

      Matcher matcher = COMPILE_TIME_GLOBAL_LINE.matcher(line);
      if (!matcher.matches()) {
        errors.add(Pair.of(CompileTimeGlobalsFileError.INVALID_FORMAT, line));
        continue;
      }
      String name = matcher.group(1);
      String valueText = matcher.group(2).trim();

      try {
        ExprNode valueExpr = (new ExpressionParser(valueText)).parseExpression().getChild(0);

        // Handle negative numbers as a special case.
        // TODO: Consider changing parser to actually parse negative numbers as primitives.
        if (valueExpr instanceof NegativeOpNode) {
          ExprNode childExpr = ((NegativeOpNode) valueExpr).getChild(0);
          if (childExpr instanceof IntegerNode) {
            compileTimeGlobalsBuilder.put(
                name, IntegerData.forValue(-((IntegerNode) childExpr).getValue()));
            continue;
          } else if (childExpr instanceof FloatNode) {
            compileTimeGlobalsBuilder.put(
                name, FloatData.forValue(-((FloatNode) childExpr).getValue()));
            continue;
          }
        }

        // Record error for non-primitives.
        // TODO: Consider allowing non-primitives (e.g. list/map literals).
        if (!(valueExpr instanceof PrimitiveNode)) {
          if (valueExpr instanceof GlobalNode || valueExpr instanceof DataRefNode) {
            errors.add(Pair.of(CompileTimeGlobalsFileError.INVALID_VALUE, line));
          } else {
            errors.add(Pair.of(CompileTimeGlobalsFileError.NON_PRIMITIVE_VALUE, line));
          }
          continue;
        }

        // Default case.
        compileTimeGlobalsBuilder.put(
            name, DataUtils.convertPrimitiveExprToData((PrimitiveNode) valueExpr));

      } catch (TokenMgrError tme) {
        errors.add(Pair.of(CompileTimeGlobalsFileError.INVALID_VALUE, line));
        continue;
      } catch (ParseException pe) {
        errors.add(Pair.of(CompileTimeGlobalsFileError.INVALID_VALUE, line));
        continue;
      }
    }

    if (errors.size() > 0) {
      StringBuilder errorMsgSb =
          new StringBuilder("Compile-time globals file contains the following errors:\n");
      for (Pair<CompileTimeGlobalsFileError, String> error : errors) {
        errorMsgSb.append("[").append(String.format("%-19s", error.first.toString()))
            .append("] ").append(error.second).append("\n");
      }
      throw SoySyntaxException.createWithoutMetaInfo(errorMsgSb.toString());
    }

    return compileTimeGlobalsBuilder.build();
  }
}
TOP

Related Classes of com.google.template.soy.SoyUtils

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.