156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson/*
256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Copyright (C) 2010 Google Inc.
356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson *
456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Licensed under the Apache License, Version 2.0 (the "License");
556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * you may not use this file except in compliance with the License.
656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * You may obtain a copy of the License at
756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson *
856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * http://www.apache.org/licenses/LICENSE-2.0
956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson *
1056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Unless required by applicable law or agreed to in writing, software
1156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * distributed under the License is distributed on an "AS IS" BASIS,
1256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * See the License for the specific language governing permissions and
1456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * limitations under the License.
1556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */
1656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
1756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonpackage com.google.clearsilver.jsilver.compiler;
1856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
1956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.autoescape.AutoEscapeOptions;
2056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.autoescape.EscapeMode;
2156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.data.Data;
2256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.data.DataContext;
2356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.data.DefaultDataContext;
2456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.data.TypeConverter;
2556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.exceptions.ExceptionUtil;
2656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.exceptions.JSilverInterpreterException;
2756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.functions.FunctionExecutor;
2856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.resourceloader.ResourceLoader;
2956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.template.DefaultRenderingContext;
3056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.template.Macro;
3156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.template.RenderingContext;
3256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.template.Template;
3356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.template.TemplateLoader;
3456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.values.Value;
3556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
3656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.IOException;
3756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.Collections;
3856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
3956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson/**
4056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Base class providing help to generated templates.
4156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson *
4256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Note, many of the methods are public as they are also used by macros.
4356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */
4456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonpublic abstract class BaseCompiledTemplate implements Template {
4556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
4656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private FunctionExecutor functionExecutor;
4756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private String templateName;
4856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private TemplateLoader templateLoader;
4956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private EscapeMode escapeMode = EscapeMode.ESCAPE_NONE;
5056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private AutoEscapeOptions autoEscapeOptions;
5156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
5256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void setFunctionExecutor(FunctionExecutor functionExecutor) {
5356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    this.functionExecutor = functionExecutor;
5456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
5556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
5656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void setTemplateName(String templateName) {
5756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    this.templateName = templateName;
5856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
5956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
6056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void setTemplateLoader(TemplateLoader templateLoader) {
6156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    this.templateLoader = templateLoader;
6256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
6356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
6456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
6556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Set auto escaping options so they can be passed to the rendering context.
6656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   *
6756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * @see AutoEscapeOptions
6856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
6956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void setAutoEscapeOptions(AutoEscapeOptions autoEscapeOptions) {
7056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    this.autoEscapeOptions = autoEscapeOptions;
7156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
7256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
7356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
7456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void render(Data data, Appendable out, ResourceLoader resourceLoader) throws IOException {
7556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
7656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    render(createRenderingContext(data, out, resourceLoader));
7756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
7856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
7956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
8056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public RenderingContext createRenderingContext(Data data, Appendable out,
8156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      ResourceLoader resourceLoader) {
8256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    DataContext dataContext = new DefaultDataContext(data);
8356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return new DefaultRenderingContext(dataContext, resourceLoader, out, functionExecutor,
8456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        autoEscapeOptions);
8556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
8656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
8756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
8856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public String getTemplateName() {
8956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return templateName;
9056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
9156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
9256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
9356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Sets the EscapeMode in which this template was generated.
9456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   *
9556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * @param mode EscapeMode
9656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
9756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void setEscapeMode(EscapeMode mode) {
9856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    this.escapeMode = mode;
9956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
10056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
10156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
10256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public EscapeMode getEscapeMode() {
10356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return escapeMode;
10456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
10556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
10656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
10756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public String getDisplayName() {
10856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return templateName;
10956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
11056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
11156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
11256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Verify that the loop arguments are valid. If not, we will skip the loop.
11356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
11456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static boolean validateLoopArgs(int start, int end, int increment) {
11556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (increment == 0) {
11656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return false; // No increment. Avoid infinite loop.
11756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
11856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (increment > 0 && start > end) {
11956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return false; // Incrementing the wrong way. Avoid infinite loop.
12056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
12156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (increment < 0 && start < end) {
12256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return false; // Incrementing the wrong way. Avoid infinite loop.
12356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
12456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return true;
12556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
12656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
12756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
12856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static boolean exists(Data data) {
12956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return TypeConverter.exists(data);
13056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
13156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
13256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static int asInt(String value) {
13356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return TypeConverter.asNumber(value);
13456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
13556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
13656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static int asInt(int value) {
13756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return value;
13856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
13956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
14056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static int asInt(boolean value) {
14156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return value ? 1 : 0;
14256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
14356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
14456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static int asInt(Value value) {
14556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return value.asNumber();
14656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
14756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
14856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static int asInt(Data data) {
14956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return TypeConverter.asNumber(data);
15056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
15156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
15256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static String asString(String value) {
15356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return value;
15456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
15556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
15656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static String asString(int value) {
15756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return Integer.toString(value);
15856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
15956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
16056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static String asString(boolean value) {
16156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return value ? "1" : "0";
16256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
16356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
16456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static String asString(Value value) {
16556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return value.asString();
16656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
16756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
16856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static String asString(Data data) {
16956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return TypeConverter.asString(data);
17056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
17156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
17256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static Value asValue(String value) {
17356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // Compiler mode does not use the Value's escapeMode or partiallyEscaped
17456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // variables. TemplateTranslator uses other means to determine the proper
17556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // escaping to apply. So just set the default escaping flags here.
17656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return Value.literalValue(value, EscapeMode.ESCAPE_NONE, false);
17756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
17856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
17956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static Value asValue(int value) {
18056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // Compiler mode does not use the Value's escapeMode or partiallyEscaped
18156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // variables. TemplateTranslator uses other means to determine the proper
18256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // escaping to apply. So just set the default escaping flags here.
18356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return Value.literalValue(value, EscapeMode.ESCAPE_NONE, false);
18456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
18556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
18656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static Value asValue(boolean value) {
18756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // Compiler mode does not use the Value's escapeMode or partiallyEscaped
18856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // variables. TemplateTranslator uses other means to determine the proper
18956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // escaping to apply. So just set the default escaping flags here.
19056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return Value.literalValue(value, EscapeMode.ESCAPE_NONE, false);
19156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
19256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
19356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static Value asValue(Value value) {
19456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return value;
19556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
19656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
19756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static Value asVariableValue(String variableName, DataContext context) {
19856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return Value.variableValue(variableName, context);
19956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
20056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
20156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static boolean asBoolean(boolean value) {
20256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return value;
20356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
20456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
20556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static boolean asBoolean(String value) {
20656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return TypeConverter.asBoolean(value);
20756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
20856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
20956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static boolean asBoolean(int value) {
21056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return value != 0;
21156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
21256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
21356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static boolean asBoolean(Value value) {
21456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return value.asBoolean();
21556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
21656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
21756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static boolean asBoolean(Data data) {
21856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return TypeConverter.asBoolean(data);
21956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
22056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
22156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
22256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Gets the name of the node for writing. Used by cs name command. Returns empty string if not
22356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * found.
22456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
22556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static String getNodeName(Data data) {
22656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return data == null ? "" : data.getSymlink().getName();
22756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
22856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
22956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
23056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Returns child nodes of parent. Parent may be null, in which case an empty iterable is returned.
23156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
23256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public Iterable<? extends Data> getChildren(Data parent) {
23356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (parent == null) {
23456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return Collections.emptySet();
23556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    } else {
23656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return parent.getChildren();
23756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
23856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
23956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
24056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  protected TemplateLoader getTemplateLoader() {
24156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return templateLoader;
24256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
24356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
24456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public abstract class CompiledMacro implements Macro {
24556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
24656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    private final String macroName;
24756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    private final String[] argumentsNames;
24856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
24956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    protected CompiledMacro(String macroName, String... argumentsNames) {
25056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      this.macroName = macroName;
25156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      this.argumentsNames = argumentsNames;
25256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
25356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
25456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    @Override
25556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    public void render(Data data, Appendable out, ResourceLoader resourceLoader) throws IOException {
25656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      render(createRenderingContext(data, out, resourceLoader));
25756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
25856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
25956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    @Override
26056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    public RenderingContext createRenderingContext(Data data, Appendable out,
26156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        ResourceLoader resourceLoader) {
26256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return BaseCompiledTemplate.this.createRenderingContext(data, out, resourceLoader);
26356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
26456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
26556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    @Override
26656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    public String getTemplateName() {
26756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return BaseCompiledTemplate.this.getTemplateName();
26856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
26956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
27056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    @Override
27156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    public String getMacroName() {
27256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return macroName;
27356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
27456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
27556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    @Override
27656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    public String getArgumentName(int index) {
27756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      if (index >= argumentsNames.length) {
27856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        // TODO: Make sure this behavior of failing if too many
27956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        // arguments are passed to a macro is consistent with JNI / interpreter.
28056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        throw new JSilverInterpreterException("Too many arguments supplied to macro " + macroName);
28156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      }
28256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return argumentsNames[index];
28356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
28456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
28556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    public int getArgumentCount() {
28656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return argumentsNames.length;
28756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
28856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
28956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    protected TemplateLoader getTemplateLoader() {
29056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return templateLoader;
29156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
29256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
29356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    @Override
29456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    public EscapeMode getEscapeMode() {
29556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return BaseCompiledTemplate.this.getEscapeMode();
29656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
29756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
29856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    @Override
29956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    public String getDisplayName() {
30056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return BaseCompiledTemplate.this.getDisplayName() + ":" + macroName;
30156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
30256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
30356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
30456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
30556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Code common to all three include commands.
30656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   *
30756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * @param templateName String representing name of file to include.
30856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * @param ignoreMissingFile {@code true} if any FileNotFound error generated by the template
30956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   *        loader should be ignored, {@code false} otherwise.
31056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * @param context Rendering context to use for the included template.
31156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
31256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  protected void include(String templateName, boolean ignoreMissingFile, RenderingContext context) {
31356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (!context.pushIncludeStackEntry(templateName)) {
31456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      throw new JSilverInterpreterException(createIncludeLoopErrorMessage(templateName, context
31556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          .getIncludedTemplateNames()));
31656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
31756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
31856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    loadAndRenderIncludedTemplate(templateName, ignoreMissingFile, context);
31956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
32056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (!context.popIncludeStackEntry(templateName)) {
32156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // Include stack trace is corrupted
32256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      throw new IllegalStateException("Unable to find on include stack: " + templateName);
32356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
32456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
32556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
32656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  // This method should ONLY be called from include()
32756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private void loadAndRenderIncludedTemplate(String templateName, boolean ignoreMissingFile,
32856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      RenderingContext context) {
32956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    Template template = null;
33056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    try {
33156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      template =
33256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          templateLoader.load(templateName, context.getResourceLoader(), context
33356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson              .getAutoEscapeMode());
33456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    } catch (RuntimeException e) {
33556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      if (ignoreMissingFile && ExceptionUtil.isFileNotFoundException(e)) {
33656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        return;
33756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      } else {
33856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        throw e;
33956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      }
34056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
34156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // Intepret loaded template.
34256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    try {
34356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      template.render(context);
34456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    } catch (IOException e) {
34556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      throw new JSilverInterpreterException(e.getMessage());
34656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
34756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
34856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
34956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private String createIncludeLoopErrorMessage(String templateName, Iterable<String> includeStack) {
35056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    StringBuilder message = new StringBuilder();
35156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    message.append("File included twice: ");
35256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    message.append(templateName);
35356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
35456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    message.append(" Include stack:");
35556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    for (String fileName : includeStack) {
35656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      message.append("\n -> ");
35756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      message.append(fileName);
35856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
35956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    message.append("\n -> ");
36056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    message.append(templateName);
36156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return message.toString();
36256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
36356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson}
364