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.misc.*;
import java.io.*;
import java.lang.reflect.Constructor;
import java.util.*;
/** This class knows how to execute template bytecodes relative to a
* particular STGroup. To execute the byte codes, we need an output stream
* and a reference to an ST an instance. That instance's impl field points at
* a 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 the group that we're executing relative to has debug set, we track
* interpreter events. For now, I am only tracking instance creation events.
* These are used by STViz to pair up output chunks with the template
* expressions that generate them.
*
* We create a new interpreter for each ST.render(), DebugST.inspect, or
* DebugST.getEvents() invocation.
*/
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 =
new HashSet() { { add("i"); add("i0"); } };
/** Operand stack, grows upwards */
Object[] operands = new Object[DEFAULT_OPERAND_STACK_SIZE];
int sp = -1; // stack pointer register
int current_ip = 0; // mirrors ip in exec(), but visible to all methods
int nwline = 0; // how many char written on this template LINE so far?
/** Stack of enclosing instances (scopes). Used for dynamic scoping
* of attributes.
*/
public InstanceScope currentScope = null;
/** Exec st with respect to this group. Once set in ST.toString(),
* it should be fixed. ST has group also.
*/
STGroup group;
/** For renderers, we have to pass in the locale */
Locale locale;
ErrorManager errMgr;
/** Dump bytecode instructions as we execute them? mainly for parrt */
public static boolean trace = false;
/** If trace mode, track trace here */
// TODO: track the pieces not a string and track what it contributes to output
protected List executeTrace;
/** Track events inside templates and in this.events */
public boolean debug = false;
/** Track everything happening in interp if debug across all templates.
* The last event in this field is the 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 self and return how many characters it wrote to out */
public int exec(STWriter out, ST self) {
pushScope(self);
try {
setDefaultArguments(out, self);
return _exec(out, self);
}
catch (Exception e) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
pw.flush();
errMgr.runTimeError(this, self, current_ip, ErrorType.INTERNAL_ERROR,
"internal error: "+sw.toString());
return 0;
}
finally { popScope(); }
}
protected int _exec(STWriter out, ST self) {
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(self, ip);
short opcode = code[ip];
//count[opcode]++;
current_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(self, name);
if ( o==ST.EMPTY_ATTR ) o = null;
}
catch (STNoSuchAttributeException nsae) {
errMgr.runTimeError(this, self, current_ip, 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, self, o, name);
break;
case Bytecode.INSTR_LOAD_PROP_IND :
Object propName = operands[sp--];
o = operands[sp];
operands[sp] = getObjectProperty(out, self, 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, self, ip, name);
// get n args and store into st's attr list
storeArgs(self, 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, self, ip, name);
storeArgs(self, 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 = (Map)operands[sp--];
// look up in original hierarchy not enclosing template (variable group)
// see TestSubtemplates.testEvalSTFromAnotherGroup()
st = self.groupThatCreatedThisInstance.getEmbeddedInstanceOf(this, self, ip, name);
// get n args and store into st's attr list
storeArgs(self, 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(self, 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 = (Map)operands[sp--];
super_new(self, 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 = (Map)operands[sp];
attrs.put(name, o); // leave attrs on stack
break;
case Bytecode.INSTR_WRITE :
o = operands[sp--];
int n1 = writeObjectNoOptions(out, self, 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, self, 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(self,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(self,o,templates);
break;
case Bytecode.INSTR_ZIP_MAP:
st = (ST)operands[sp--];
nmaps = getShort(code, ip);
ip += Bytecode.OPND_SIZE_IN_BYTES;
List