![JAR search and dependency download from the Maven repository](/logo.png)
org.mvel2.templates.TemplateCompiler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of tbel Show documentation
Show all versions of tbel Show documentation
TBEL is a powerful expression language for ThingsBoard platform user-defined functions.
Original implementation is based on MVEL.
/**
* MVEL 2.0
* Copyright (C) 2007 The Codehaus
* Mike Brock, Dhanji Prasanna, John Graham, Mark Proctor
*
* 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 org.mvel2.templates;
import org.mvel2.CompileException;
import org.mvel2.ParserContext;
import org.mvel2.templates.res.*;
import org.mvel2.templates.util.TemplateTools;
import org.mvel2.util.ExecutionStack;
import org.mvel2.util.ParseTools;
import java.io.File;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import static org.mvel2.util.ParseTools.balancedCaptureWithLineAccounting;
import static org.mvel2.util.ParseTools.subset;
/**
* The TemplateCompiler class is used for pre-compiling MVEL Templates. To execute a compiled template see
* {@link TemplateRuntime}
*
* @author Mike Brock
*/
@SuppressWarnings({"ManualArrayCopy"})
public class TemplateCompiler {
private char[] template;
private int length;
private int start;
private int cursor;
private int lastTextRangeEnding;
private int line;
private int colStart;
private boolean codeCache = false;
private Map> customNodes;
private ParserContext parserContext;
private static final Map OPCODES = new HashMap();
static {
OPCODES.put("if", Opcodes.IF);
OPCODES.put("else", Opcodes.ELSE);
OPCODES.put("elseif", Opcodes.ELSE);
OPCODES.put("end", Opcodes.END);
OPCODES.put("foreach", Opcodes.FOREACH);
OPCODES.put("includeNamed", Opcodes.INCLUDE_NAMED);
OPCODES.put("include", Opcodes.INCLUDE_FILE);
OPCODES.put("comment", Opcodes.COMMENT);
OPCODES.put("code", Opcodes.CODE);
OPCODES.put("eval", Opcodes.EVAL);
OPCODES.put("declare", Opcodes.DECLARE);
OPCODES.put("stop", Opcodes.STOP);
}
public CompiledTemplate compile() {
return new CompiledTemplate(template, compileFrom(null, new ExecutionStack()));
}
public Node compileFrom(Node root, ExecutionStack stack) {
line = 1;
Node n = root;
if (root == null) {
n = root = new TextNode(0, 0);
}
IfNode last;
Integer opcode;
String name;
int x;
try {
while (cursor < length) {
switch (template[cursor]) {
case '\n':
line++;
colStart = cursor + 1;
break;
case '@':
case '$':
if (isNext(template[cursor])) {
start = ++cursor;
(n = markTextNode(n)).setEnd(n.getEnd() + 1);
start = lastTextRangeEnding = ++cursor;
continue;
}
if ((x = captureOrbToken()) != -1) {
start = x;
switch ((opcode = OPCODES.get(name = new String(capture()))) == null ? 0 : opcode) {
case Opcodes.IF:
/**
* Capture any residual text node, and push the if statement on the nesting stack.
*/
stack.push(n = markTextNode(n).next =
codeCache ? new CompiledIfNode(start, name, template, captureOrbInternal(), start, parserContext)
: new IfNode(start, name, template, captureOrbInternal(), start));
n.setTerminus(new TerminalNode());
break;
case Opcodes.ELSE:
if (!stack.isEmpty() && stack.peek() instanceof IfNode) {
markTextNode(n).next = (last = (IfNode) stack.pop()).getTerminus();
last.demarcate(last.getTerminus(), template);
last.next = n = codeCache ? new CompiledIfNode(start, name, template, captureOrbInternal(), start, parserContext)
: new IfNode(start, name, template, captureOrbInternal(), start);
n.setTerminus(last.getTerminus());
stack.push(n);
}
break;
case Opcodes.FOREACH:
stack.push(
n = markTextNode(n).next = codeCache ? new CompiledForEachNode(start, name, template, captureOrbInternal(), start, parserContext)
: new ForEachNode(start, name, template, captureOrbInternal(), start)
);
n.setTerminus(new TerminalNode());
break;
case Opcodes.INCLUDE_FILE:
n = markTextNode(n).next =
codeCache ? new CompiledIncludeNode(start, name, template, captureOrbInternal(), start = cursor + 1, parserContext)
: new IncludeNode(start, name, template, captureOrbInternal(), start = cursor + 1);
break;
case Opcodes.INCLUDE_NAMED:
n = markTextNode(n).next =
codeCache ? new CompiledNamedIncludeNode(start, name, template, captureOrbInternal(), start = cursor + 1, parserContext)
: new NamedIncludeNode(start, name, template, captureOrbInternal(), start = cursor + 1);
break;
case Opcodes.CODE:
n = markTextNode(n)
.next = codeCache ? new CompiledCodeNode(start, name, template, captureOrbInternal(), start = cursor + 1, parserContext)
: new CodeNode(start, name, template, captureOrbInternal(), start = cursor + 1);
break;
case Opcodes.EVAL:
n = markTextNode(n).next =
codeCache ? new CompiledEvalNode(start, name, template, captureOrbInternal(), start = cursor + 1, parserContext)
: new EvalNode(start, name, template, captureOrbInternal(), start = cursor + 1);
break;
case Opcodes.COMMENT:
n = markTextNode(n)
.next = new CommentNode(start, name, template, captureOrbInternal(), start = cursor + 1);
break;
case Opcodes.DECLARE:
stack.push(n = markTextNode(n).next =
codeCache ?
new CompiledDeclareNode(start, name, template, captureOrbInternal(), start = cursor + 1, parserContext)
: new DeclareNode(start, name, template, captureOrbInternal(), start = cursor + 1));
n.setTerminus(new TerminalNode());
break;
case Opcodes.END:
n = markTextNode(n);
Node end = (Node) stack.pop();
Node terminal = end.getTerminus();
terminal.setCStart(captureOrbInternal());
terminal.setEnd((lastTextRangeEnding = start) - 1);
terminal.calculateContents(template);
if (end.demarcate(terminal, template)) n = n.next = terminal;
else n = terminal;
break;
default:
if (name.length() == 0) {
n = markTextNode(n).next =
codeCache ?
new CompiledExpressionNode(start, name, template, captureOrbInternal(), start = cursor + 1, parserContext)
: new ExpressionNode(start, name, template, captureOrbInternal(), start = cursor + 1);
}
else if (customNodes != null && customNodes.containsKey(name)) {
Class extends Node> customNode = customNodes.get(name);
try {
(n = markTextNode(n).next = (customNode.newInstance())).setBegin(start);
n.setName(name);
n.setCStart(captureOrbInternal());
n.setCEnd(start = cursor + 1);
n.setEnd(n.getCEnd());
n.setContents(subset(template, n.getCStart(), n.getCEnd() - n.getCStart() - 1));
if (n.isOpenNode()) {
stack.push(n);
}
}
catch (InstantiationException e) {
throw new RuntimeException("unable to instantiate custom node class: " + customNode.getName());
}
catch (IllegalAccessException e) {
throw new RuntimeException("unable to instantiate custom node class: " + customNode.getName());
}
}
else {
throw new RuntimeException("unknown token type: " + name);
}
}
}
break;
}
cursor++;
}
}
catch (RuntimeException e) {
CompileException ce = new CompileException(e.getMessage(), template, cursor, e);
ce.setExpr(template);
if (e instanceof CompileException) {
CompileException ce2 = (CompileException) e;
if (ce2.getCursor() != -1) {
ce.setCursor(ce2.getCursor());
if (ce2.getColumn() == -1) ce.setColumn(ce.getCursor() - colStart);
else ce.setColumn(ce2.getColumn());
}
}
ce.setLineNumber(line);
throw ce;
}
if (!stack.isEmpty()) {
CompileException ce = new CompileException("unclosed @" + ((Node) stack.peek()).getName() + "{} block. expected @end{}", template, cursor);
ce.setColumn(cursor - colStart);
ce.setLineNumber(line);
throw ce;
}
if (start < template.length) {
n = n.next = new TextNode(start, template.length);
}
n.next = new EndNode();
n = root;
do {
if (n.getLength() != 0) {
break;
}
}
while ((n = n.getNext()) != null);
if (n != null && n.getLength() == template.length - 1) {
if (n instanceof ExpressionNode) {
return codeCache ? new CompiledTerminalExpressionNode(n, parserContext) : new TerminalExpressionNode(n);
}
else {
return n;
}
}
return root;
}
// Parse Utilities Start Here
private boolean isNext(char c) {
return cursor != length && template[cursor + 1] == c;
}
private int captureOrbToken() {
int newStart = ++cursor;
while ((cursor != length) && ParseTools.isIdentifierPart(template[cursor])) cursor++;
if (cursor != length && template[cursor] == '{') return newStart;
return -1;
}
private int captureOrbInternal() {
try {
ParserContext pCtx = new ParserContext();
cursor = balancedCaptureWithLineAccounting(template, start = cursor, length, '{', pCtx);
line += pCtx.getLineCount();
int ret = start + 1;
start = cursor + 1;
return ret;
}
catch (CompileException e) {
e.setLineNumber(line);
e.setColumn((cursor - colStart) + 1);
throw e;
}
}
private char[] capture() {
char[] newChar = new char[cursor - start];
for (int i = 0; i < newChar.length; i++) {
newChar[i] = template[i + start];
}
return newChar;
}
private Node markTextNode(Node n) {
int s = (n.getEnd() > lastTextRangeEnding ? n.getEnd() : lastTextRangeEnding);
if (s < start) {
return n.next = new TextNode(s, lastTextRangeEnding = start - 1);
}
return n;
}
public ParserContext getParserContext() {
return parserContext;
}
public static CompiledTemplate compileTemplate(String template) {
return new TemplateCompiler(template, true, ParserContext.create()).compile();
}
public static CompiledTemplate compileTemplate(char[] template) {
return new TemplateCompiler(template, true, ParserContext.create()).compile();
}
public static CompiledTemplate compileTemplate(CharSequence template) {
return new TemplateCompiler(template, true, ParserContext.create()).compile();
}
public static CompiledTemplate compileTemplate(String template, ParserContext context) {
return new TemplateCompiler(template, true, context).compile();
}
public static CompiledTemplate compileTemplate(char[] template, ParserContext context) {
return new TemplateCompiler(template, true, context).compile();
}
public static CompiledTemplate compileTemplate(CharSequence template, ParserContext context) {
return new TemplateCompiler(template, true, context).compile();
}
public static CompiledTemplate compileTemplate(String template, Map> customNodes) {
return new TemplateCompiler(template, customNodes, true, ParserContext.create()).compile();
}
public static CompiledTemplate compileTemplate(char[] template, Map> customNodes) {
return new TemplateCompiler(template, customNodes, true, ParserContext.create()).compile();
}
public static CompiledTemplate compileTemplate(CharSequence template, Map> customNodes) {
return new TemplateCompiler(template, customNodes, true, ParserContext.create()).compile();
}
public static CompiledTemplate compileTemplate(String template, Map> customNodes,
ParserContext context) {
return new TemplateCompiler(template, customNodes, true, context).compile();
}
public static CompiledTemplate compileTemplate(char[] template, Map> customNodes,
ParserContext context) {
return new TemplateCompiler(template, customNodes, true, context).compile();
}
public static CompiledTemplate compileTemplate(CharSequence template, Map> customNodes,
ParserContext context) {
return new TemplateCompiler(template, customNodes, true, context).compile();
}
public static CompiledTemplate compileTemplate(InputStream stream) {
return compileTemplate(stream, ParserContext.create());
}
public static CompiledTemplate compileTemplate(InputStream stream, ParserContext context) {
return compileTemplate(stream, null, context);
}
public static CompiledTemplate compileTemplate(InputStream stream, Map> customNodes) {
return new TemplateCompiler(TemplateTools.readStream(stream), customNodes, true, ParserContext.create()).compile();
}
public static CompiledTemplate compileTemplate(InputStream stream, Map> customNodes,
ParserContext context) {
return new TemplateCompiler(TemplateTools.readStream(stream), customNodes, true, context).compile();
}
public static CompiledTemplate compileTemplate(File file) {
return compileTemplate(file, ParserContext.create());
}
public static CompiledTemplate compileTemplate(File file, ParserContext context) {
return compileTemplate(file, null, context);
}
public static CompiledTemplate compileTemplate(File file, Map> customNodes) {
return new TemplateCompiler(TemplateTools.readInFile(file), customNodes, true, ParserContext.create()).compile();
}
public static CompiledTemplate compileTemplate(File file, Map> customNodes,
ParserContext context) {
return new TemplateCompiler(TemplateTools.readInFile(file), customNodes, true, context).compile();
}
public TemplateCompiler(String template) {
this.length = (this.template = template.toCharArray()).length;
}
public TemplateCompiler(char[] template) {
this.length = (this.template = template).length;
}
public TemplateCompiler(String template, boolean codeCache) {
this.length = (this.template = template.toCharArray()).length;
this.codeCache = codeCache;
}
public TemplateCompiler(char[] template, boolean codeCache) {
this.length = (this.template = template).length;
this.codeCache = codeCache;
}
public TemplateCompiler(char[] template, boolean codeCache, ParserContext context) {
this.length = (this.template = template).length;
this.codeCache = codeCache;
this.parserContext = context;
}
public TemplateCompiler(CharSequence sequence) {
this.length = (this.template = sequence.toString().toCharArray()).length;
}
public TemplateCompiler(CharSequence sequence, boolean codeCache) {
this.length = (this.template = sequence.toString().toCharArray()).length;
this.codeCache = codeCache;
}
public TemplateCompiler(CharSequence sequence, boolean codeCache, ParserContext context) {
this.length = (this.template = sequence.toString().toCharArray()).length;
this.codeCache = codeCache;
this.parserContext = context;
}
public TemplateCompiler(String template, Map> customNodes) {
this.length = (this.template = template.toCharArray()).length;
this.customNodes = customNodes;
}
public TemplateCompiler(char[] template, Map> customNodes) {
this.length = (this.template = template).length;
this.customNodes = customNodes;
}
public TemplateCompiler(CharSequence sequence, Map> customNodes) {
this.length = (this.template = sequence.toString().toCharArray()).length;
this.customNodes = customNodes;
}
public TemplateCompiler(String template, Map> customNodes, boolean codeCache) {
this.length = (this.template = template.toCharArray()).length;
this.customNodes = customNodes;
this.codeCache = codeCache;
}
public TemplateCompiler(char[] template, Map> customNodes, boolean codeCache) {
this.length = (this.template = template).length;
this.customNodes = customNodes;
this.codeCache = codeCache;
}
public TemplateCompiler(CharSequence sequence, Map> customNodes, boolean codeCache) {
this.length = (this.template = sequence.toString().toCharArray()).length;
this.customNodes = customNodes;
this.codeCache = codeCache;
}
public TemplateCompiler(String template, Map> customNodes, boolean codeCache,
ParserContext context) {
this.length = (this.template = template.toCharArray()).length;
this.customNodes = customNodes;
this.codeCache = codeCache;
this.parserContext = context;
}
public TemplateCompiler(char[] template, Map> customNodes, boolean codeCache,
ParserContext context) {
this.length = (this.template = template).length;
this.customNodes = customNodes;
this.codeCache = codeCache;
this.parserContext = context;
}
public TemplateCompiler(CharSequence sequence, Map> customNodes, boolean codeCache,
ParserContext context) {
this.length = (this.template = sequence.toString().toCharArray()).length;
this.customNodes = customNodes;
this.codeCache = codeCache;
this.parserContext = context;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy