/**
* Copyright 2008 - 2015
*
* 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.
*
* @project loon
* @author cping
* @email:javachenpeng@yahoo.com
* @version 0.5
*/
package loon.action.avg.drama;
import loon.BaseIO;
import loon.Json;
import loon.LSystem;
import loon.utils.Array;
import loon.utils.ArrayMap;
import loon.utils.MathUtils;
import loon.utils.StringUtils;
import loon.utils.TArray;
/*
* Loon默认提供的脚本解释器,无平台依赖,用来实现一种近似于Processing的线型渲染与操作,
* 另外,RocScript中也允许使用Command中的命令.
*/
public class RocScript {
private Command macros_executer = null;
private TArray<IMacros> macros_listeners = new TArray<IMacros>(10);
private final IScriptLog scriptLog;
private static ArrayMap waitTimes = new ArrayMap();
static {
waitTimes.put("mesc", LSystem.MSEC);
waitTimes.put("second", LSystem.SECOND);
waitTimes.put("minute", LSystem.MINUTE);
waitTimes.put("hour", LSystem.HOUR);
waitTimes.put("day", LSystem.DAY);
}
private void handleError(int error) throws ScriptException {
String[] errors = new String[UNKNOWN + 1];
errors[SYNTAX] = "Syntax Error";
errors[UNBALPARENS] = "(... or ...)";
errors[DIVBYZERO] = "1/0";
errors[EQUALEXPECTED] = "Equal Expected";
errors[UNKOWN] = "For vars that have no value: assignments,loops";
errors[NOTABOOL] = "Not a boolean";
errors[NOTANUMB] = "Not a number";
errors[NOTASTR] = " Not a string";
errors[DUPFUNCTION] = "Two functions with same name";
errors[ENDEXPECTED] = "Reaches end of script without end";
errors[THENEXPECTED] = "No then after if";
errors[DOEXPECTED] = "No then after if";
errors[MISSQUOTE] = "Strings missing a quote";
errors[UNKFUNCTION] = "Unknown function";
errors[INVALIDEXP] = "Invalid Expression";
errors[UNEXPITEM] = "Unexpeced Item";
errors[FILENOTFOUND] = "Can't find file";
errors[INPUTIOERROR] = "Input that fails";
errors[EXPERR] = "For if, while and for";
errors[FILEIOERROR] = "Can't load file";
errors[UNKNOWN] = "Unknown error";
String err = errors[error] + ": " + textIdx + "\nLine number: "
+ textLine + "\nItem: " + item + "\nItem Type: " + itemType
+ "\ncommType: " + commType + "\npreviousitem: " + previousItem;
if (scriptLog != null) {
scriptLog.err(err);
}
throw new ScriptException(err);
}
private final static int MAX_TEXT_SIZE = 65535;
private RocFunctions _rocFunctions = null;
// 参数类型
private final int NONE = 0; // 不存在
private final int DELIMITER = 1; // 任意特殊符号
private final int VARIABLE = 2; // 已经存在的变量
private final int COMMAND = 3; // 接下来的命令
private final int EOL = 4; // 结束一行
private final int EOP = 5; // 结束全部文本
// 判定参数类型
private final int STRING = 6;
private final int NUMBER = 7;
private final int BOOLEAN = 8;
private final int FUNCT = 9;
// 脚本指令
// 条件
private final int UNKNCOM = 0;
private final int PRINT = 1;
private final int INPUT = 2;
private final int RETURN = 3;
private final int THEN = 4;
private final int END = 5;
private final int BEGIN = 6;
private final int ELSE = 7;
// 分支
private final int IF = 8;
private final int FOR = 9;
private final int WHILE = 10;
private final int FUNCTION = 11;
// 延迟
private final int WAIT = 12;
private final int PRINTLN = 13;
// 错误
private final int SYNTAX = 0;
private final int UNBALPARENS = 1;
private final int DIVBYZERO = 2;
private final int EQUALEXPECTED = 3;
private final int UNKOWN = 4;
private final int NOTABOOL = 5;
private final int NOTANUMB = 6;
private final int NOTASTR = 7;
private final int DUPFUNCTION = 8;
private final int ENDEXPECTED = 9;
private final int THENEXPECTED = 10;
private final int MISSQUOTE = 11;
private final int DOEXPECTED = 12;
private final int UNKFUNCTION = 13;
private final int INVALIDEXP = 14;
private final int UNEXPITEM = 15;
private final int TOOMANYPARAMS = 16;
private final int FILENOTFOUND = 17;
private final int INPUTIOERROR = 18;
private final int EXPERR = 19;
private final int FILEIOERROR = 20;
// 宏
private final int MACROS = 21;
// 未知区域
private final int UNKNOWN = 22;
// 宏指令设置
private boolean initNextMacros = true;
// 保存脚本用
private Array<LoonFun> commands;
// 变量
private Array<ArrayMap> vars;
// 函数
private ArrayMap functs;
private char[] _temp_contexts;
protected long _sleep = -1;
private boolean _stop = false;
private int textIdx;
private int textLine;
private String item, previousItem;
private int itemType;
private int commType;
private int macroType = -1;
// <=
private final char LE = 0;
// >=
private final char GE = 1;
// ==
private final char EQ = 4;
private final char rOps[] = { LE, GE, '<', '>', EQ };
private String relops = new String(rOps);
private final char AND = 0;
private final char OR = 1;
private final char NOT = 2;
private final char XOR = 3;
private final char XAND = 4;
private final char selectOpsId[] = { AND, OR, NOT, XOR, XAND };
private final String selectOps[] = { "and", "or", "not", "xor", "xand" };
private String[] commTable = { "", "print", "input", "return", "then",
"end", "begin", "else", "if", "for", "while", "function", "wait",
"println" };
private String[] macros = { "{", "}" };
private boolean debug = true;
private final boolean DEBUG_E = false;
public class ScriptException extends Exception {
/**
*
*/
private static final long serialVersionUID = 1L;
String errStr;
public ScriptException(String str) {
this.errStr = str;
}
@Override
public String toString() {
return errStr;
}
}
class LoonFun {
int loc, comm = 0, line;
@Override
public String toString() {
return commTable[comm];
}
}
class ForLoop extends LoonFun {
String vName;
int expLoc, itLoc;
public ForLoop(String n, int exp, int it, int lo, int lin) {
comm = FOR;
vName = n;
expLoc = exp;
itLoc = it;
loc = lo;
line = lin;
}
public ForLoop() {
comm = FOR;
}
}
class WhileLoop extends LoonFun {
int expLoc, line;
public WhileLoop(int exp, int lo, int lin) {
comm = WHILE;
expLoc = exp;
loc = lo;
line = lin;
}
public WhileLoop() {
comm = WHILE;
}
}
class Function extends LoonFun {
int backLoc;
TArray<String> lists;
public Function(int l, int bLoc, TArray<String> pars) {
comm = FUNCTION;
backLoc = bLoc;
loc = l;
lists = pars;
}
public Function() {
comm = FUNCTION;
}
}
class IfStat extends LoonFun {
boolean done;
public IfStat(boolean d) {
comm = IF;
done = d;
}
}
private void splitFlag(String src, StringBuffer out, char flag) {
char[] chars = src.toCharArray();
for (int i = 0; i < chars.length; i++) {
char ch = chars[i];
if (ch == flag) {
out.append(flag);
if (i + 1 < chars.length && chars[i + 1] != '\n') {
out.append(LSystem.LS);
}
} else {
out.append(ch);
}
}
}
private String filtrScript(String script) {
StringBuffer out = new StringBuffer();
String[] context = StringUtils.split(script, new char[] { '\r', '\n',
'\t' }, true);
for (String c : context) {
if (c == null) {
continue;
}
String cmd = c.toLowerCase().trim();
if (cmd.startsWith("print") && cmd.indexOf("\"") != -1
&& cmd.indexOf(",") == -1) {
char[] chars = cmd.toCharArray();
boolean flag = false;
for (int i = 0; i < chars.length; i++) {
if (chars[i] == '"') {
flag = !flag;
}
if (!flag) {
if (chars[i] == '+') {
chars[i] = ',';
}
}
}
cmd = new String(chars);
}
if (cmd.indexOf('{') != -1) {
splitFlag(cmd, out, '{');
} else {
out.append(cmd);
}
out.append(LSystem.LS);
}
return out.toString();
}
/**
* 构建脚本
*
* @param script
* @param useFile
* @throws ScriptException
*/
public RocScript(String script, boolean useFile) throws ScriptException {
this(new DefScriptLog(), script, useFile);
}
/**
* 构建脚本
*
* @param log
* @param script
* @param useFile
* @throws ScriptException
*/
public RocScript(IScriptLog log, String script, boolean useFile)
throws ScriptException {
this._rocFunctions = new RocFunctions();
this.scriptLog = log;
debug("Loading file...");
char[] charlist = new char[MAX_TEXT_SIZE];
int size = 0;
// 文件名导入
if (useFile) {
try {
String text = BaseIO.loadText(script);
charlist = filtrScript(text).toCharArray();
size = charlist.length;
} catch (Exception exc) {
handleError(FILEIOERROR);
}
// 当读取到文件尾部时,后退一位
if (charlist[size - 1] == (char) 26) {
size--;
}
} else {
charlist = filtrScript(script).toCharArray();
size = charlist.length;
}
if (size > MAX_TEXT_SIZE) {
size = MAX_TEXT_SIZE;
}
if (size != -1) {
_temp_contexts = new char[size];
System.arraycopy(charlist, 0, _temp_contexts, 0, size);
}
}
private void debug(String s) {
if (debug) {
if (commands != null) {
for (int i = 0; i < commands.size(); i++)
scriptLog.line("\t");
}
scriptLog.err("> " + s);
}
}
private void debug(String[] strs) {
if (debug) {
String str = "";
if (commands != null) {
for (int i = 0; i < commands.size(); i++)
str += "\t";
}
for (String s : strs) {
scriptLog.err(str + s);
}
}
}
/**
* 指定脚本程序
*
* @param de
* @throws ScriptException
*/
public void call(boolean de) {
debug("Running script...");
setDebug(de);
// 初始化寄存器
vars = new Array<ArrayMap>();
vars.add(new ArrayMap());
functs = new ArrayMap();
commands = new Array<LoonFun>();
item = null;
textIdx = 0;
textLine = 1;
itemType = 0;
commType = 0;
macroType = -1;
}
/**
* 重新运行脚本
*/
public void reset() {
call(this.debug);
resetWait();
}
public void setDebug(boolean de) {
this.debug = de;
}
public boolean isDebug() {
return this.debug;
}
public void stop() {
_stop = true;
}
/**
* 执行脚本命令
*
* @return
* @throws ScriptException
*/
public Object next() throws ScriptException {
try {
debug("Starting script...");
if (_sleep != -1) {
return null;
}
for (; !isCompleted() && nextItem() && !_stop;) {
if (item != null) {
item = item.trim();
}
switch (itemType) {
// 变量
case VARIABLE:
assignVar();
break;
// 函数
case FUNCT:
execFunct();
nextItem();
break;
// 具体表达式变量
case COMMAND:
switch (commType) {
case PRINT:
print();
break;
case PRINTLN:
println();
break;
case INPUT:
break;
case IF:
execIf();
break;
case FOR:
execFor();
break;
case END:
if (endCommand(false)) {
return null;
}
break;
case WHILE:
execWhile();
break;
case RETURN:
debug("Returning");
nextItem();
Object o = analysis();
endCommand(true);
return o;
case FUNCTION:
newFunction();
break;
case ELSE:
execElse();
break;
case WAIT:
debug("waiting");
break;
}
debug("Done with command");
break;
// 宏指令
case MACROS:
switch (macroType) {
case 0:
callMacros();
itemType = EOL;
break;
case 1:
itemType = EOL;
break;
}
break;
}
// 判定解析完毕
if (itemType != EOL && itemType != EOP) {
handleError(UNEXPITEM);
}
if (_sleep != -1) {
return null;
}
}
} finally {
previousItem = item;
}
return null;
}
public Object running() throws ScriptException {
try {
debug("Starting script...");
if (nextItem() && !_stop) {
if (item != null) {
item = item.trim();
}
switch (itemType) {
// 变量
case VARIABLE:
assignVar();
break;
// 函数
case FUNCT:
execFunct();
nextItem();
break;
// 具体表达式变量
case COMMAND:
switch (commType) {
case PRINT:
print();
break;
case PRINTLN:
println();
break;
case INPUT:
break;
case IF:
execIf();
break;
case FOR:
execFor();
break;
case END:
if (endCommand(false)) {
return null;
}
break;
case WHILE:
execWhile();
break;
case RETURN:
debug("Returning");
nextItem();
Object o = analysis();
endCommand(true);
return o;
case FUNCTION:
newFunction();
break;
case ELSE:
execElse();
break;
case WAIT:
debug("waiting");
break;
}
debug("Done with command");
break;
// 宏指令
case MACROS:
switch (macroType) {
case 0:
callMacros();
itemType = EOL;
break;
case 1:
itemType = EOL;
break;
}
break;
}
// 判定解析完毕
if (itemType != EOL && itemType != EOP) {
handleError(UNEXPITEM);
}
}
} finally {
previousItem = item;
}
return null;
}
public void setCallMacros(boolean f) {
this.initNextMacros = f;
}
public boolean isCallMacros() {
return this.initNextMacros;
}
private void callMacros() throws ScriptException {
nextItem();
debug("Macros:");
debug(item);
macrosCommand(this.item, this.textLine);
}
public void setMacrosListener(TArray<IMacros> list) {
if (list == null) {
return;
}
this.macros_listeners = list;
}
public void setMacrosListener(IMacros... args) {
if (args == null) {
return;
}
for (int i = 0; i < args.length; i++) {
this.macros_listeners.add(args[i]);
}
}
public void setMacrosListener(IMacros macros) {
addMacrosListener(macros);
}
public void addMacrosListener(IMacros macros) {
if (this.macros_listeners != null && macros != null) {
this.macros_listeners.add(macros);
}
}
private void macrosCommand(String context, int id) {
if (!initNextMacros) {
return;
}
Command.resetCache();
String[] res = StringUtils.split(context, '\n');
if (macros_executer == null) {
macros_executer = new Command("script" + id, res);
} else {
macros_executer.formatCommand("script" + id, res);
}
for (int i = 0; i < vars.size(); i++) {
ArrayMap maps = vars.get(i);
macros_executer.setVariables(maps);
}
if (scriptLog != null) {
scriptLog.info("Syncing...");
}
for (; macros_executer.next();) {
String result = macros_executer.doExecute();
if (result == null) {
continue;
}
if (macros_listeners != null) {
for (IMacros macros_listener : macros_listeners) {
macros_listener.call(scriptLog, textLine, macros_executer,
result);
}
}
}
if (scriptLog != null) {
scriptLog.info("Synchro is completed.");
}
vars.add(macros_executer.getVariables());
}
private void println() throws ScriptException {
debug("Println");
String lastDelim = "";
while (nextItem() && itemType != EOL && itemType != EOP) {
scriptLog.info(analysis());
lastDelim = item;
if (lastDelim.equals(",")) {
scriptLog.line(" ");
} else if (lastDelim.equals(";")) {
scriptLog.line("\t");
} else if (itemType != EOL && itemType != EOP) {
handleError(SYNTAX);
} else {
break;
}
}
}
private void print() throws ScriptException {
debug("Print");
String lastDelim = "";
while (nextItem() && itemType != EOL && itemType != EOP) {
scriptLog.line(analysis());
lastDelim = item;
if (lastDelim.equals(",")) {
scriptLog.line(" ");
} else if (lastDelim.equals(";")) {
scriptLog.line("\t");
} else if (itemType != EOL && itemType != EOP) {
handleError(SYNTAX);
} else {
break;
}
}
}
private void execIf() throws ScriptException {
debug("If select");
boolean result = false;
nextItem();
try {
Object o = analysis();
if (o instanceof Boolean) {
result = (boolean) o;
} else if (o instanceof Number) {
result = Double.parseDouble(o.toString()) > 0;
}
} catch (ClassCastException exc) {
handleError(NOTABOOL);
return;
}
vars.add(new ArrayMap());
commands.add(new IfStat(result));
if (result) {
if (commType != THEN) {
handleError(THENEXPECTED);
return;
}
nextItem();
} else {
nextEnd();
}
}
private void execElse() throws ScriptException {
debug("Else select");
LoonFun c = commands.last();
if (c.comm != IF) {
handleError(SYNTAX);
return;
}
if (!((IfStat) c).done) {
nextItem();
if (commType == IF) {
nextItem();
boolean result;
try {
result = (boolean) analysis();
} catch (ClassCastException exc) {
handleError(NOTABOOL);
return;
}
if (result) {
((IfStat) c).done = true;
if (commType != THEN) {
handleError(THENEXPECTED);
return;
}
nextItem();
} else {
nextEnd();
}
return;
}
} else {
nextEnd();
}
}
// 循环执行
private void execFor() throws ScriptException {
debug("For Loop");
double i;
int expLoc, ittLoc, loc;
String vname;
nextItem();
vname = item;
// =
nextItem();
if (item.equals("=")) {
nextItem();
try {
i = (double) analysis();
} catch (ClassCastException exc) {
handleError(EXPERR);
return;
}
vars.last().put(vname, i);
}
// ,
if (!item.equals(",")) {
handleError(SYNTAX);
return;
}
expLoc = textIdx;
nextItem();
try {
if (!(boolean) analysis()) {
vars.add(new ArrayMap());
commands.add(new ForLoop());
nextEnd();
return;
}
} catch (ClassCastException exc) {
handleError(NOTABOOL);
}
if (!item.equals(",")) {
handleError(SYNTAX);
return;
}
ittLoc = textIdx;
nextItem();
analysis();
if (commType != BEGIN) {
handleError(DOEXPECTED);
return;
}
loc = textIdx;
nextItem();
ForLoop newfor;
try {
newfor = new ForLoop(vname, expLoc, ittLoc, loc, textLine);
} catch (ClassCastException exc) {
handleError(EXPERR);
return;
}
vars.add(new ArrayMap());
commands.add(newfor);
}
private void execWhile() throws ScriptException {
debug("While Loop");
int expLoc;
expLoc = textIdx;
nextItem();
try {
if (!(boolean) analysis()) {
vars.add(new ArrayMap());
commands.add(new WhileLoop());
nextEnd();
return;
}
} catch (ClassCastException exc) {
handleError(NOTABOOL);
}
if (commType != BEGIN) {
handleError(DOEXPECTED);
return;
}
int loc = textIdx;
nextItem();
WhileLoop loop = new WhileLoop(expLoc, loc, textLine);
vars.add(new ArrayMap());
commands.add(loop);
}
private void newFunction() throws ScriptException {
debug("New Function");
String fName;
nextItem();
if (!(Character.isLetter(item.charAt(0)))) {
handleError(UNKOWN);
}
fName = item;
nextItem();
if (!item.equals("(")) {
handleError(SYNTAX);
}
nextItem();
TArray<String> lists = new TArray<String>();
if (!item.equals(")")) {
if (Character.isLetter(item.charAt(0))) {
lists.add(item);
while (nextItem() && item.equals(",")) {
nextItem();
lists.add(item);
}
if (!item.equals(")")) {
handleError(SYNTAX);
}
} else {
handleError(UNKOWN);
return;
}
}
nextItem();
if (!(commType == BEGIN)) {
handleError(SYNTAX);
}
Function f = new Function(textIdx, -1, lists);
functs.put(fName.toLowerCase(), f);
vars.add(new ArrayMap());
commands.add(f);
nextEnd();
nextItem();
}
private Object execFunct() throws ScriptException {
debug("Execute Function");
if (_rocFunctions._system_functs.contains(item.trim().toLowerCase())) {
String key = item;
nextItem();
if (!item.equals("(")) {
handleError(UNBALPARENS);
return null;
}
nextItem();
String value = "";
if (!item.equals(")")) {
while (item.indexOf(")") == -1) {
value += item;
nextItem();
}
if (!item.equals(")")) {
handleError(UNBALPARENS);
return null;
}
}
if (value.length() > 0 && value.indexOf(",") == -1) {
if (value.indexOf("\"") == -1 && value.indexOf("/") == -1
&& !isNumber(value)) {
String tmp = getVarVal(value).toString();
if (!"unkown".equalsIgnoreCase(tmp)) {
value = tmp;
}
}
} else if (value.indexOf(",") != -1) {
String[] split = StringUtils.split(value, ',');
StringBuilder sbr = new StringBuilder();
for (String s : split) {
if (s.indexOf("\"") == -1 && value.indexOf("/") == -1
&& !isNumber(s)) {
String tmp = getVarVal(s).toString();
if (!"unkown".equalsIgnoreCase(tmp)) {
sbr.append(tmp.toString());
} else {
sbr.append(s);
}
} else {
sbr.append(s);
}
sbr.append(',');
}
value = sbr.toString();
if (value.endsWith(",")) {
value = value.substring(0, value.length() - 1);
}
}
Object reuslt = _rocFunctions.getValue(this, key, value);
return reuslt == null ? "unkown" : reuslt;
}
Function f = (Function) functs.get(item.toLowerCase());
nextItem();
if (!item.equals("(")) {
handleError(UNBALPARENS);
return null;
}
nextItem();
ArrayMap newVars = new ArrayMap();
int i = 0;
if (!item.equals(")")) {
newVars.put(f.lists.get(i++), analysis());
while (item.equals(",")) {
nextItem();
newVars.put(f.lists.get(i++), analysis());
}
if (f.lists.size < i) {
handleError(TOOMANYPARAMS);
}
if (!item.equals(")")) {
handleError(UNBALPARENS);
return null;
}
}
f.backLoc = textIdx;
vars.add(newVars);
commands.add(f);
textIdx = f.loc;
return next();
}
private boolean endCommand(boolean force) throws ScriptException {
debug("End LoonFun");
if (force) {
while (commands.last().comm != FUNCTION) {
commands.pop();
}
}
LoonFun p = commands.last();
if (p == null) {
handleError(SYNTAX);
}
switch (p.comm) {
case IF:
nextItem();
passBack();
commands.pop();
return false;
case FOR:
int loc = textIdx;
ForLoop f = (ForLoop) p;
if (f.loc > 0) {
textIdx = f.itLoc;
nextItem();
vars.last().put(f.vName, (double) analysis());
textIdx = f.expLoc;
nextItem();
if ((boolean) analysis()) {
textIdx = f.loc;
textLine = f.line;
} else {
passBack();
commands.pop();
textIdx = loc;
}
} else {
passBack();
commands.pop();
}
nextItem();
return false;
case WHILE:
loc = textIdx;
WhileLoop w = (WhileLoop) p;
if (w.loc > 0) {
textIdx = w.expLoc;
nextItem();
if ((boolean) analysis()) {
textIdx = w.loc;
textLine = w.line;
} else {
passBack();
commands.pop();
textIdx = loc;
}
} else {
passBack();
commands.pop();
}
nextItem();
return false;
case FUNCTION:
loc = textIdx;
Function funct = (Function) p;
if (funct.backLoc > 0) {
textIdx = funct.backLoc;
}
passBack();
commands.pop();
return true;
}
return false;
}
private void nextEnd() throws ScriptException {
debug("Next end");
int count = 1;
while (count > 0 && nextItem()) {
if (commType > 7 && commType != PRINTLN) {
count++;
debug("Find End: " + count);
}
if (commType == END) {
count--;
debug("Find End: " + count);
}
if (commType == ELSE) {
if (count == 1) {
execElse();
return;
} else if (nextItem() && commType == IF) {
debug("Find End: " + count);
}
}
}
if (commType != END) {
handleError(ENDEXPECTED);
return;
}
endCommand(false);
}
/**
* 检查脚本是否解析完毕
*
* @return
*/
public boolean isCompleted() {
return this.itemType == EOP;
}
/**
* 单纯判定脚本命令是否存在,以及向下移动一次命令行
*
* @return
* @throws ScriptException
*/
private boolean nextItem() throws ScriptException {
boolean result = nextCommand();
debug(new String[] { "Item: " + item, "CommandStack: " + commands,
"Type: " + itemType });
return result;
}
/**
* 分步检索脚本命令
*
* @return
* @throws ScriptException
*/
private boolean nextCommand() throws ScriptException {
if (itemType == MACROS && macroType != -1) {
char flag = macros[1].toCharArray()[0];
StringBuffer sbr = new StringBuffer(1024);
while (textIdx < _temp_contexts.length) {
char ch = _temp_contexts[textIdx++];
if (flag == ch) {
break;
}
sbr.append(ch);
}
item = sbr.toString();
itemType = EOL;
macroType = -1;
return true;
}
char ch = ' ';
item = "";
itemType = NONE;
commType = UNKNCOM;
macroType = -1;
while (textIdx < _temp_contexts.length
&& isSpaceOrTab(_temp_contexts[textIdx])) {
textIdx++;
}
if (textIdx >= _temp_contexts.length) {
itemType = EOP;
item = " ";
return false;
}
if (_temp_contexts[textIdx] == '\r') {
textIdx += 2;
itemType = EOL;
item = " ";
textLine++;
return true;
}
ch = _temp_contexts[textIdx];
if (ch == '#'
|| (ch == '/' && textIdx + 1 < _temp_contexts.length && _temp_contexts[textIdx + 1] == '/')) {
while (textIdx < _temp_contexts.length
&& _temp_contexts[textIdx] != '\r') {
textIdx++;
}
textIdx += 2;
itemType = EOL;
item = " ";
textLine++;
return true;
}
if (ch == '<' || ch == '>' || ch == '=') {
switch (ch) {
case '<':
if (_temp_contexts[textIdx + 1] == '=') {
item = String.valueOf(LE);
textIdx += 2;
} else {
item = "<";
textIdx++;
}
break;
case '>':
if (_temp_contexts[textIdx + 1] == '=') {
item = String.valueOf(GE);
textIdx += 2;
} else {
item = ">";
textIdx++;
}
break;
case '=':
if (_temp_contexts[textIdx + 1] == '=') {
item = String.valueOf(EQ);
textIdx += 2;
} else {
item = "=";
textIdx++;
}
break;
}
itemType = DELIMITER;
return true;
}
if (isDelim(ch)) {
item += _temp_contexts[textIdx];
textIdx++;
itemType = DELIMITER;
return true;
} else if (ch == '"') {
textIdx++;
ch = _temp_contexts[textIdx];
while (ch != '"' && ch != '\r') {
item += ch;
textIdx++;
ch = _temp_contexts[textIdx];
}
if (ch == '\r') {
handleError(MISSQUOTE);
return false;
}
textIdx++;
itemType = STRING;
return true;
} else {
while (textIdx < _temp_contexts.length
&& !isDelim(_temp_contexts[textIdx])) {
item += _temp_contexts[textIdx];
textIdx++;
}
if (isNumber(item)) {
itemType = NUMBER;
return true;
} else if (isBoolean(item)) {
itemType = BOOLEAN;
return true;
} else {
// 匹配命令
itemType = lookup(item);
if (itemType == UNKNCOM) {
itemType = VARIABLE;
}
if (commType == WAIT) {
item = "";
int count = 0;
while (textIdx < _temp_contexts.length) {
ch = _temp_contexts[textIdx];
if ((ch == ' ') || (ch == '\n') || (ch == '\t')
|| (ch == '\r')) {
count++;
}
if (count > 1) {
break;
}
if (ch != ' ') {
item += _temp_contexts[textIdx];
}
textIdx++;
}
long sleep = 0;
if (isNumber(item)) {
sleep = (long) Double.parseDouble(item);
} else {
sleep = (long) waitTimes.get(item.toLowerCase());
}
if (sleep <= 0) {
sleep = 1;
}
_sleep = sleep;
nextItem();
}
return true;
}
}
}
public long waitSleep() {
return _sleep;
}
public void resetWait() {
this._sleep = -1;
}
private Object analysis() throws ScriptException {
debug("Analysis");
Object result;
if (item.equals(EOL) || item.equals(EOP)) {
handleError(EXPERR);
}
result = evalExp1();
debug("Analysis end: " + result);
return result;
}
private Object evalExp1() throws ScriptException {
Object result, pResult;
double l_temp, r_temp;
boolean lb, rb;
String ls, rs;
char op;
String str;
result = evalExp2();
op = item.charAt(0);
str = item.toLowerCase();
while (isRelOp(op) || isBoolOp(str)) {
nextItem();
if (isNumber(result)) {
pResult = evalExp2();
if (isRelOp(op)) {
if (isNumber(result)) {
l_temp = (double) result;
r_temp = (double) pResult;
switch (op) {
case '<':
result = (l_temp < r_temp);
break;
case LE:
result = (l_temp <= r_temp);
break;
case '>':
result = (l_temp > r_temp);
break;
case GE:
result = (l_temp >= r_temp);
break;
case EQ:
result = (l_temp == r_temp);
break;
}
} else {
handleError(NOTANUMB);
result = null;
}
}
} else if (isBoolean(result)) {
pResult = evalExp1();
if (isBoolOp(str)) {
if (isBoolean(result)) {
lb = (boolean) result;
rb = (boolean) pResult;
switch (str) {
case "and":
result = (lb && rb);
break;
case "or":
result = (lb || rb);
break;
case "xor":
result = (lb ^ rb);
break;
case "xand":
result = (lb == rb);
break;
}
} else {
handleError(NOTABOOL);
result = null;
}
}
} else {
if (isRelOp(op)) {
pResult = evalExp2();
if (!isNumber(result)) {
rs = (String) pResult;
ls = (String) result;
double test = (ls.compareTo(rs));
switch (op) {
case '<':
result = test < 0;
break;
case LE:
result = test <= 0;
break;
case '>':
result = test > 0;
break;
case GE:
result = test >= 0;
break;
case EQ:
result = test == 0;
break;
}
} else {
handleError(NOTASTR);
result = null;
}
}
}
op = item.charAt(0);
str = item.toLowerCase();
}
if (DEBUG_E) {
debug("1: " + result);
}
return result;
}
private Object evalExp2() throws ScriptException {
char op;
Object result;
Object pResult;
result = evalExp3();
while ((op = item.charAt(0)) == '+' || op == '-') {
nextItem();
pResult = evalExp3();
if (isNumber(result)) {
if (isNumber(pResult)) {
switch (op) {
case '-':
result = (double) result - (double) pResult;
break;
case '+':
result = (double) result + (double) pResult;
break;
}
} else {
handleError(NOTANUMB);
return null;
}
} else if (!isBoolean(result)) {
if (!isNumber(pResult) && !isBoolean(pResult)) {
switch (op) {
case '-':
handleError(INVALIDEXP);
case '+':
result = (String) result + (String) pResult;
break;
}
} else {
handleError(NOTASTR);
return null;
}
}
}
if (DEBUG_E) {
debug("2: " + result);
}
return result;
}
private Object evalExp3() throws ScriptException {
char op;
Object result;
Object partialResult;
result = evalExp4();
while ((op = item.charAt(0)) == '*' || op == '/' || op == '%') {
if (!isNumber(result)) {
handleError(NOTANUMB);
return null;
}
nextItem();
partialResult = evalExp4();
if (!isNumber(partialResult)) {
handleError(NOTANUMB);
return null;
}
switch (op) {
case '*':
result = (double) result * (double) partialResult;
break;
case '/':
if ((double) partialResult == 0.0)
handleError(DIVBYZERO);
result = (double) result / (double) partialResult;
break;
case '%':
if ((double) partialResult == 0.0)
handleError(DIVBYZERO);
result = (double) result % (double) partialResult;
break;
}
}
if (DEBUG_E) {
debug("3: " + result);
}
return result;
}
private Object evalExp4() throws ScriptException {
Object result;
Object partialResult;
double ex;
double t;
result = evalExp5();
if (item.equals("^")) {
if (!isNumber(result)) {
handleError(NOTANUMB);
return null;
}
nextItem();
partialResult = evalExp4();
if (!isNumber(partialResult)) {
handleError(NOTANUMB);
return null;
}
ex = (double) result;
if ((double) partialResult == 0.0) {
result = 1.0;
} else {
for (t = (double) partialResult - 1; t > 0; t--) {
result = (double) result * ex;
}
}
}
if (DEBUG_E) {
debug("4: " + result);
}
return result;
}
private Object evalExp5() throws ScriptException {
Object result;
String op = item;
if (item.equals("-") || item.toLowerCase().equals(selectOps[NOT])) {
nextItem();
result = evalExp6();
if (isNumber(result)) {
if (op.equals("-"))
result = -(double) result;
else {
handleError(NOTABOOL);
return null;
}
} else if (isBoolean(result)) {
if (op.toLowerCase().equals(selectOps[NOT]))
result = !(boolean) result;
else {
handleError(NOTANUMB);
return null;
}
} else {
handleError(INVALIDEXP);
return null;
}
} else {
result = evalExp6();
}
if (DEBUG_E) {
debug("5: " + result);
}
return result;
}
private Object evalExp6() throws ScriptException {
Object result;
if (item.equals("(")) {
nextItem();
result = evalExp1();
if (!item.equals(")")) {
handleError(UNBALPARENS);
}
nextItem();
return result;
} else {
result = atom();
nextItem();
}
if (DEBUG_E) {
debug("6: " + result);
}
return result;
}
private Object atom() throws ScriptException {
switch (itemType) {
case FUNCT:
return execFunct();
case NUMBER:
try {
return Double.parseDouble(item);
} catch (NumberFormatException exc) {
handleError(NOTANUMB);
}
case VARIABLE:
Object o = getVarVal(item);
if (o instanceof Number) {
return (Number) o;
} else if (isNumber(o)) {
if (DEBUG_E) {
debug("atom: " + o.toString());
}
return Double.parseDouble(o.toString());
}
if (o instanceof Boolean) {
return (boolean) o;
} else if (isBoolean(o)) {
return StringUtils.toBoolean((String) o);
}
return o;
case BOOLEAN:
return StringUtils.toBoolean(item);
case STRING:
return item;
default:
return null;
}
}
private boolean isDelim(char c) {
if ((" \r,<>+-/*%^=();#".indexOf(c) != -1)) {
return true;
}
return false;
}
boolean isSpaceOrTab(char c) {
if (c == ' ' || c == '\t') {
return true;
}
return false;
}
protected boolean isRelOp(char c) {
if (relops.indexOf(c) != -1) {
return true;
}
return false;
}
protected boolean isBoolOp(String str) {
for (int i = 0; i < selectOps.length; i++) {
if (selectOps[i].equals(str)) {
return true;
}
}
return false;
}
protected boolean isBoolOpId(int id) {
for (int i = 0; i < selectOpsId.length; i++) {
if (selectOpsId[i] == id) {
return true;
}
}
return false;
}
protected boolean isBoolean(Object o) {
String str = o.toString().toLowerCase();
return str.equals("true") || str.equals("false") || str.equals("yes")
|| str.equals("no") || str.equals("ok") || MathUtils.isNan(str);
}
protected boolean isNumber(Object o) {
String str = o.toString();
return MathUtils.isNan(str);
}
private int lookup(String str) {
int i;
str = StringUtils.rtrim(str.toLowerCase());
// 判定是否已定义的变量
for (int j = 0; j < vars.size(); j++) {
ArrayMap tm = vars.get(j);
if (tm.containsKey(str)) {
return VARIABLE;
}
}
// 判定是否已定义的函数
if (functs.containsKey(str)
|| _rocFunctions._system_functs.contains(str.trim()
.toLowerCase())) {
return FUNCT;
}
// 判定是否分支指令
for (i = 0; i < selectOps.length; i++) {
if (selectOps[i].equals(str)) {
return DELIMITER;
}
}
// 判定是否存在于命令表中
for (i = 0; i < commTable.length; i++) {
if (commTable[i].equals(str)) {
commType = i;
return COMMAND;
}
}
// 判定是否为宏指令
for (i = 0; i < macros.length; i++) {
if (macros[i].equals(str)) {
macroType = i;
return MACROS;
}
}
return UNKNCOM;
}
private void assignVar() throws ScriptException {
debug("Assign variable");
String var = item;
if (!Character.isLetter(var.charAt(0))) {
handleError(UNKOWN);
return;
}
nextItem();
if (!item.equals("=")) {
handleError(EQUALEXPECTED);
return;
}
nextItem();
Object obj = analysis();
vars.last().put(var, obj);
}
private void passBack() {
ArrayMap tvars = vars.pop();
for (int i = 0; i < tvars.size(); i++) {
String str = (String) tvars.getKey(i);
if (vars.last().containsKey(str)) {
vars.last().put(str, tvars.get(str));
}
}
}
private Object[] findVar(String vname) {
Object o = null;
int idx = vname.lastIndexOf('.');
if (idx == -1) {
return null;
}
String name = vname.substring(0, idx);
for (int i = 0; i < vars.size(); i++) {
ArrayMap tm = vars.get(i);
if (tm.containsKey(name)) {
o = tm.get(name);
break;
}
}
if (o != null) {
String method = vname.substring(idx + 1, vname.length());
return new Object[] { name, method, o };
}
return findVar(name);
}
/**
* 查询指定的json对象元素(暂时未使用递归,预防有不愿展露的数据被穷举出来)
*
* @param value
* @param vname
* @param method
* @return
*/
private Object queryJson(Object value, String vname, String method) {
int start = 0;
int end = 0;
Object o = null;
Json.Object json = (Json.Object) value;
if (json.containsKey(method)) {
o = json.getObject(method);
}
if (!vname.equals(method)) {
start = vname.indexOf(method);
int size = start + method.length() + 1;
String packName = "";
if (size >= vname.length()) {
packName = method;
} else {
packName = vname.substring(size, vname.length());
}
json = (Json.Object) o;
if (packName.indexOf("[") != -1 && packName.indexOf("]") != -1) {
if (packName.indexOf(".") == -1) {
start = packName.indexOf('[');
end = packName.indexOf(']');
String idxName = packName.substring(start + 1, end);
packName = packName.substring(0, start);
if (json.containsKey(packName)) {
o = json.getObject(packName);
if (o != null && o instanceof Json.Array) {
Json.Array arrays = (Json.Array) o;
int idx = 0;
try {
idx = (int) Double.parseDouble(idxName);
} catch (Exception ex) {
idx = 0;
}
if (idx < arrays.length()) {
o = arrays.getObject(idx);
} else {
o = null;
}
}
}
} else {
String[] split = StringUtils.split(packName, ".");
Object obj = null;
for (String n : split) {
if (obj == null) {
if (n.indexOf("[") != -1 && n.indexOf("]") != -1) {
if (n.indexOf(".") == -1) {
start = n.indexOf('[');
end = n.indexOf(']');
String idxName = n
.substring(start + 1, end);
n = n.substring(0, start);
if (json.containsKey(n)) {
obj = json.getObject(n);
if (obj != null
&& obj instanceof Json.Array) {
Json.Array arrays = (Json.Array) obj;
int idx = 0;
try {
idx = (int) Double
.parseDouble(idxName);
} catch (Exception ex) {
idx = 0;
}
if (idx < arrays.length()) {
obj = arrays.getObject(idx);
} else {
obj = null;
}
}
}
}
} else {
if (packName.indexOf(".") == -1) {
if (o != null && o instanceof Json.Object) {
if (json.containsKey(packName)) {
o = json.getObject(packName);
}
}
} else {
if (o != null && o instanceof Json.Object) {
String[] splits = StringUtils.split(
packName, ',');
Object v = null;
for (String s : splits) {
if (v == null) {
if (json.containsKey(s)) {
v = json.getObject(s);
}
} else {
if (v instanceof Json.Object) {
if (((Json.Object) v)
.containsKey(s)) {
v = ((Json.Object) v)
.getObject(s);
}
}
}
}
}
}
}
} else {
if (n.indexOf("[") != -1 && n.indexOf("]") != -1) {
if (n.indexOf(".") == -1) {
start = n.indexOf('[');
end = n.indexOf(']');
String idxName = n
.substring(start + 1, end);
n = n.substring(0, start);
if (((Json.Object) obj).containsKey(n)) {
obj = ((Json.Object) obj).getObject(n);
if (obj != null
&& obj instanceof Json.Array) {
Json.Array arrays = (Json.Array) obj;
int idx = 0;
try {
idx = (int) Double
.parseDouble(idxName);
} catch (Exception ex) {
idx = 0;
}
if (idx < arrays.length()) {
obj = arrays.getObject(idx);
} else {
obj = null;
}
}
}
}
} else if (n.indexOf(".") == -1) {
if (obj != null && obj instanceof Json.Object) {
if (((Json.Object) obj).containsKey(n)) {
obj = ((Json.Object) obj).getObject(n);
}
}
} else {
if (obj != null && obj instanceof Json.Object) {
String[] splits = StringUtils.split(n, ',');
Object v = null;
for (String s : splits) {
if (v == null) {
if (((Json.Object) obj)
.containsKey(s)) {
v = ((Json.Object) obj)
.getObject(s);
}
} else {
if (v instanceof Json.Object) {
if (((Json.Object) v)
.containsKey(s)) {
v = ((Json.Object) v)
.getObject(s);
}
}
}
}
}
}
}
}
o = obj;
}
} else {
if (packName.indexOf(".") == -1) {
if (o != null && o instanceof Json.Object) {
if (json.containsKey(packName)) {
o = json.getObject(packName);
}
}
} else {
if (o != null && o instanceof Json.Object) {
String[] split = StringUtils.split(packName, ',');
Object v = null;
for (String n : split) {
if (v == null) {
if (json.containsKey(n)) {
v = json.getObject(n);
}
} else {
if (v instanceof Json.Object) {
if (((Json.Object) v).containsKey(n)) {
v = ((Json.Object) v).getObject(n);
}
}
}
}
}
}
}
}
return o;
}
private Object getVarVal(String vname) throws ScriptException {
if (vname.indexOf('\'') == 0 || vname.indexOf('\"') == 0) {
if (vname.length() > 2) {
return vname.substring(1, vname.length() - 1);
}
return vname;
}
if (!Character.isLetter(vname.charAt(0))) {
handleError(UNKOWN);
return 0;
}
Object o = null;
for (int i = 0; i < vars.size(); i++) {
ArrayMap tm = vars.get(i);
if (tm.containsKey(vname)) {
o = tm.get(vname);
}
}
if (o == null) {
o = findVar(vname);
if (o != null) {
Object[] result = (Object[]) o;
String method = (String) result[1];
Object value = result[2];
if (value instanceof Json.Object) {
o = queryJson(value, vname, method);
} else {
o = value;
}
}
}
if (o == null) {
o = "unkown";
}
debug("Get var: " + o);
return o;
}
public RocFunctions getFunctions() {
return _rocFunctions;
}
public void setFunctions(RocFunctions roc) {
this._rocFunctions = roc;
}
/**
* 在脚本外本注入变量
*
* @param name
* @param obj
*/
public void addVar(String name, Object obj) {
if (vars != null) {
vars.last().put(name, obj);
}
}
/**
* 获得指定名称的脚本变量
*
* @param name
* @return
*/
public Object getLastVar(String name) {
if (vars != null) {
return vars.last().get(name);
}
return null;
}
/**
* 获得指定名称的脚本变量
*
* @param name
* @return
*/
public Object getFirstVar(String name) {
if (vars != null) {
return vars.first().get(name);
}
return null;
}
/**
* 获得指定名称的脚本变量
*
* @param name
* @return
*/
public Object getVar(String name) {
if (vars != null) {
Object result = null;
for (; vars.hashNext();) {
ArrayMap map = vars.next();
if (map != null) {
result = map.get(name);
if (result != null) {
return result;
}
}
}
vars.stopNext();
return vars.last().get(name);
}
return null;
}
@Override
public String toString() {
return "{" + new String(_temp_contexts) + "}";
}
}