Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
StringTemplate is a java template engine for generating source code,
web pages, emails, or any other formatted text output.
StringTemplate is particularly good at multi-targeted code generators,
multiple site skins, and internationalization/localization.
It evolved over years of effort developing jGuru.com.
StringTemplate also powers the ANTLR 3 and 4 code generator. Its distinguishing characteristic
is that unlike other engines, it strictly enforces model-view separation.
Strict separation makes websites and code generators more flexible
and maintainable; it also provides an excellent defense against malicious
template authors.
/*
* [The "BSD license"]
* Copyright (c) 2011 Terence Parr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.stringtemplate.v4;
import org.stringtemplate.v4.compiler.*;
import org.stringtemplate.v4.compiler.Compiler;
import org.stringtemplate.v4.debug.*;
import org.stringtemplate.v4.gui.STViz;
import org.stringtemplate.v4.misc.*;
import java.io.*;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.util.*;
/**
* This class knows how to execute template bytecodes relative to a particular
* {@link STGroup}. To execute the byte codes, we need an output stream and a
* reference to an {@link ST} instance. That instance's {@link ST#impl} field
* points at a {@link CompiledST}, which contains all of the byte codes and
* other information relevant to execution.
*
* This interpreter is a stack-based bytecode interpreter. All operands go onto
* an operand stack.
*
* If {@link #debug} set, we track interpreter events. For now, I am only
* tracking instance creation events. These are used by {@link STViz} to pair up
* output chunks with the template expressions that generate them.
*
* We create a new interpreter for each invocation of
* {@link ST#render}, {@link ST#inspect}, or {@link ST#getEvents}.
*/
public class Interpreter {
public enum Option { ANCHOR, FORMAT, NULL, SEPARATOR, WRAP }
public static final int DEFAULT_OPERAND_STACK_SIZE = 100;
public static final Set predefinedAnonSubtemplateAttributes;
static {
final Set set = new HashSet();
set.add("i");
set.add("i0");
predefinedAnonSubtemplateAttributes = Collections.unmodifiableSet(set);
}
/** Operand stack, grows upwards. */
Object[] operands = new Object[DEFAULT_OPERAND_STACK_SIZE];
/** Stack pointer register. */
int sp = -1;
/** The number of characters written on this template line so far. */
int nwline = 0;
/** Render template with respect to this group.
*
* @see ST#groupThatCreatedThisInstance
* @see CompiledST#nativeGroup
*/
STGroup group;
/** For renderers, we have to pass in the locale. */
Locale locale;
ErrorManager errMgr;
/**
* Dump bytecode instructions as they are executed. This field is mostly for
* StringTemplate development.
*/
public static boolean trace = false;
/** If {@link #trace} is {@code true}, track trace here. */
// TODO: track the pieces not a string and track what it contributes to output
protected List executeTrace;
/** When {@code true}, track events inside templates and in {@link #events}. */
public boolean debug = false;
/**
* Track everything happening in interpreter across all templates if
* {@link #debug}. The last event in this field is the
* {@link EvalTemplateEvent} for the root template.
*/
protected List events;
public Interpreter(STGroup group, boolean debug) {
this(group,Locale.getDefault(),group.errMgr, debug);
}
public Interpreter(STGroup group, Locale locale, boolean debug) {
this(group, locale, group.errMgr, debug);
}
public Interpreter(STGroup group, ErrorManager errMgr, boolean debug) {
this(group,Locale.getDefault(),errMgr, debug);
}
public Interpreter(STGroup group, Locale locale, ErrorManager errMgr, boolean debug) {
this.group = group;
this.locale = locale;
this.errMgr = errMgr;
this.debug = debug;
if ( debug ) {
events = new ArrayList();
executeTrace = new ArrayList();
}
}
// public static int[] count = new int[Bytecode.MAX_BYTECODE+1];
// public static void dumpOpcodeFreq() {
// System.out.println("#### instr freq:");
// for (int i=1; i<=Bytecode.MAX_BYTECODE; i++) {
// System.out.println(count[i]+" "+Bytecode.instructions[i].name);
// }
// }
/** Execute template {@code self} and return how many characters it wrote to {@code out}.
*
* @return the number of characters written to {@code out}
*/
public int exec(STWriter out, InstanceScope scope) {
final ST self = scope.st;
if ( trace ) System.out.println("exec("+self.getName()+")");
try {
setDefaultArguments(out, scope);
return _exec(out, scope);
}
catch (Exception e) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
pw.flush();
errMgr.runTimeError(this, scope, ErrorType.INTERNAL_ERROR,
"internal error: "+sw.toString());
return 0;
}
}
protected int _exec(STWriter out, InstanceScope scope) {
final ST self = scope.st;
int start = out.index(); // track char we're about to write
int prevOpcode = 0;
int n = 0; // how many char we write out
int nargs;
int nameIndex;
int addr;
String name;
Object o, left, right;
ST st;
Object[] options;
byte[] code = self.impl.instrs; // which code block are we executing
int ip = 0;
while ( ip < self.impl.codeSize ) {
if ( trace || debug ) trace(scope, ip);
short opcode = code[ip];
//count[opcode]++;
scope.ip = ip;
ip++; //jump to next instruction or first byte of operand
switch (opcode) {
case Bytecode.INSTR_LOAD_STR :
// just testing...
load_str(self,ip);
ip += Bytecode.OPND_SIZE_IN_BYTES;
break;
case Bytecode.INSTR_LOAD_ATTR :
nameIndex = getShort(code, ip);
ip += Bytecode.OPND_SIZE_IN_BYTES;
name = self.impl.strings[nameIndex];
try {
o = getAttribute(scope, name);
if ( o==ST.EMPTY_ATTR ) o = null;
}
catch (STNoSuchAttributeException nsae) {
errMgr.runTimeError(this, scope, ErrorType.NO_SUCH_ATTRIBUTE, name);
o = null;
}
operands[++sp] = o;
break;
case Bytecode.INSTR_LOAD_LOCAL:
int valueIndex = getShort(code, ip);
ip += Bytecode.OPND_SIZE_IN_BYTES;
o = self.locals[valueIndex];
if ( o==ST.EMPTY_ATTR ) o = null;
operands[++sp] = o;
break;
case Bytecode.INSTR_LOAD_PROP :
nameIndex = getShort(code, ip);
ip += Bytecode.OPND_SIZE_IN_BYTES;
o = operands[sp--];
name = self.impl.strings[nameIndex];
operands[++sp] = getObjectProperty(out, scope, o, name);
break;
case Bytecode.INSTR_LOAD_PROP_IND :
Object propName = operands[sp--];
o = operands[sp];
operands[sp] = getObjectProperty(out, scope, o, propName);
break;
case Bytecode.INSTR_NEW :
nameIndex = getShort(code, ip);
ip += Bytecode.OPND_SIZE_IN_BYTES;
name = self.impl.strings[nameIndex];
nargs = getShort(code, ip);
ip += Bytecode.OPND_SIZE_IN_BYTES;
// look up in original hierarchy not enclosing template (variable group)
// see TestSubtemplates.testEvalSTFromAnotherGroup()
st = self.groupThatCreatedThisInstance.getEmbeddedInstanceOf(this, scope, name);
// get n args and store into st's attr list
storeArgs(scope, nargs, st);
sp -= nargs;
operands[++sp] = st;
break;
case Bytecode.INSTR_NEW_IND:
nargs = getShort(code, ip);
ip += Bytecode.OPND_SIZE_IN_BYTES;
name = (String)operands[sp-nargs];
st = self.groupThatCreatedThisInstance.getEmbeddedInstanceOf(this, scope, name);
storeArgs(scope, nargs, st);
sp -= nargs;
sp--; // pop template name
operands[++sp] = st;
break;
case Bytecode.INSTR_NEW_BOX_ARGS :
nameIndex = getShort(code, ip);
ip += Bytecode.OPND_SIZE_IN_BYTES;
name = self.impl.strings[nameIndex];
Map attrs = (ArgumentsMap)operands[sp--];
// look up in original hierarchy not enclosing template (variable group)
// see TestSubtemplates.testEvalSTFromAnotherGroup()
st = self.groupThatCreatedThisInstance.getEmbeddedInstanceOf(this, scope, name);
// get n args and store into st's attr list
storeArgs(scope, attrs, st);
operands[++sp] = st;
break;
case Bytecode.INSTR_SUPER_NEW :
nameIndex = getShort(code, ip);
ip += Bytecode.OPND_SIZE_IN_BYTES;
name = self.impl.strings[nameIndex];
nargs = getShort(code, ip);
ip += Bytecode.OPND_SIZE_IN_BYTES;
super_new(scope, name, nargs);
break;
case Bytecode.INSTR_SUPER_NEW_BOX_ARGS :
nameIndex = getShort(code, ip);
ip += Bytecode.OPND_SIZE_IN_BYTES;
name = self.impl.strings[nameIndex];
attrs = (ArgumentsMap)operands[sp--];
super_new(scope, name, attrs);
break;
case Bytecode.INSTR_STORE_OPTION:
int optionIndex = getShort(code, ip);
ip += Bytecode.OPND_SIZE_IN_BYTES;
o = operands[sp--]; // value to store
options = (Object[])operands[sp]; // get options
options[optionIndex] = o; // store value into options on stack
break;
case Bytecode.INSTR_STORE_ARG:
nameIndex = getShort(code, ip);
name = self.impl.strings[nameIndex];
ip += Bytecode.OPND_SIZE_IN_BYTES;
o = operands[sp--];
attrs = (ArgumentsMap)operands[sp];
attrs.put(name, o); // leave attrs on stack
break;
case Bytecode.INSTR_WRITE :
o = operands[sp--];
int n1 = writeObjectNoOptions(out, scope, o);
n += n1;
nwline += n1;
break;
case Bytecode.INSTR_WRITE_OPT :
options = (Object[])operands[sp--]; // get options
o = operands[sp--]; // get option to write
int n2 = writeObjectWithOptions(out, scope, o, options);
n += n2;
nwline += n2;
break;
case Bytecode.INSTR_MAP :
st = (ST)operands[sp--]; // get prototype off stack
o = operands[sp--]; // get object to map prototype across
map(scope,o,st);
break;
case Bytecode.INSTR_ROT_MAP :
int nmaps = getShort(code, ip);
ip += Bytecode.OPND_SIZE_IN_BYTES;
List templates = new ArrayList();
for (int i=nmaps-1; i>=0; i--) templates.add((ST)operands[sp-i]);
sp -= nmaps;
o = operands[sp--];
if ( o!=null ) rot_map(scope,o,templates);
break;
case Bytecode.INSTR_ZIP_MAP:
st = (ST)operands[sp--];
nmaps = getShort(code, ip);
ip += Bytecode.OPND_SIZE_IN_BYTES;
List