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.interpreter;
1856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
1956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.autoescape.EscapeMode;
2056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.data.Data;
2156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.exceptions.JSilverInterpreterException;
2256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.resourceloader.ResourceLoader;
2356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.PCommand;
2456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.template.Macro;
2556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.template.RenderingContext;
2656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.template.Template;
2756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
2856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.IOException;
2956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
3056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson/**
3156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * User defined macro that will be executed by the interpreter.
3256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson *
3356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * NOTE: This is not thread safe and cannot be shared between RenderingContexts. This is taken care
3456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * of by the TemplateInterpreter.
3556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */
3656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonpublic class InterpretedMacro implements Macro {
3756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
3856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private final PCommand command;
3956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private final Template owningTemplate;
4056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private final String macroName;
4156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private final String[] argumentNames;
4256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private final TemplateInterpreter templateInterpreter;
4356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private final RenderingContext owningContext;
4456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
4556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public InterpretedMacro(PCommand command, Template owningTemplate, String macroName,
4656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      String[] argumentNames, TemplateInterpreter templateInterpreter,
4756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      RenderingContext owningContext) {
4856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    this.command = command;
4956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    this.owningTemplate = owningTemplate;
5056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    this.macroName = macroName;
5156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    this.argumentNames = argumentNames;
5256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    this.templateInterpreter = templateInterpreter;
5356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    this.owningContext = owningContext;
5456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
5556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
5656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
5756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void render(RenderingContext context) throws IOException {
5856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    assert context == owningContext : "Cannot render macro defined in another context";
5956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    context.pushExecutionContext(this);
6056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    boolean doRuntimeAutoEscaping = !(context.isRuntimeAutoEscaping());
6156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (doRuntimeAutoEscaping) {
6256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      context.startRuntimeAutoEscaping();
6356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
6456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    command.apply(templateInterpreter);
6556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (doRuntimeAutoEscaping) {
6656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      context.stopRuntimeAutoEscaping();
6756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
6856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    context.popExecutionContext();
6956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
7056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
7156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
7256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void render(Data data, Appendable out, ResourceLoader resourceLoader) throws IOException {
7356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    render(createRenderingContext(data, out, resourceLoader));
7456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
7556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
7656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
7756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public RenderingContext createRenderingContext(Data data, Appendable out,
7856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      ResourceLoader resourceLoader) {
7956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return owningTemplate.createRenderingContext(data, out, resourceLoader);
8056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
8156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
8256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
8356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public String getTemplateName() {
8456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return owningTemplate.getTemplateName();
8556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
8656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
8756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
8856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public EscapeMode getEscapeMode() {
8956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return owningTemplate.getEscapeMode();
9056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
9156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
9256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
9356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public String getDisplayName() {
9456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return owningTemplate.getDisplayName() + ":" + macroName;
9556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
9656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
9756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
9856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public String getMacroName() {
9956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return macroName;
10056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
10156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
10256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
10356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public String getArgumentName(int index) {
10456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (index >= argumentNames.length) {
10556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // TODO: Make sure this behavior of failing if too many
10656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // arguments are passed to a macro is consistent with JNI / interpreter.
10756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      throw new JSilverInterpreterException("Too many arguments supplied to macro " + macroName);
10856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
10956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return argumentNames[index];
11056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
11156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
11256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
11356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public int getArgumentCount() {
11456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return argumentNames.length;
11556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
11656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson}
117