diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..e7914b5e851425ccba8f9b5d66c0fe9236417d7d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,20 @@
+# Created by .ignore support plugin (hsz.mobi)
+### Java template
+*.class
+
+target/*
+*.iml
+.idea/
+
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.ear
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..0bc760587766c6a448e4db30759c338db45f2240
--- /dev/null
+++ b/README.md
@@ -0,0 +1,249 @@
+## qlExpress相关文档
+
+### 最简单的调用案例
+
+```xml
+
+ com.taobao.util
+ taobao-express
+ 3.0.17
+
+```
+
+```java
+
+ ExpressRunner runner = new ExpressRunner();
+ DefaultContext context = new DefaultContext();
+ context.put("a",1);
+ context.put("b",2);
+ context.put("c",3);
+ String express = "a+b*c";
+ Object r = runner.execute(express, context, null, true, false);
+ System.out.println(r);
+```
+
+### 更多的语法介绍
+1、java的绝大多数语法
+
+```
+//支持 +,-,*,/,<,>,<=,>=,==,!=,<>【等同于!=】,%,mod【取模等同于%】,++,--,
+//in【类似sql】,like【sql语法】,&&,||,!,等操作符
+//支持for,break、continue、if then else 等标准的程序控制逻辑
+n=10;
+for(sum=0,i=0;ib?a:b;
+
+```
+
+//关于对象,类,属性,方法的调用
+
+```
+import com.ql.util.express.test.OrderQuery;
+//系统自动会import java.lang.*,import java.util.*;
+
+
+query = new OrderQuery();//创建class实例,会根据classLoader信息,自动补全类路径
+query.setCreateDate(new Date());//设置属性
+query.buyer = "张三";//调用属性,默认会转化为setBuyer("张三")
+result = bizOrderDAO.query(query);//调用bean对象的方法
+System.out.println(result.getId());//静态方法
+
+
+//自定义方法与调用
+function add(int a,int b){
+ return a+b;
+};
+
+function sub(int a,int b){
+ return a - b;
+};
+
+a=10;
+return add(a,4) + sub(a,9);
+
+ ```
+
+2、自定义操作符号:addOperatorWithAlias+addOperator+addFunction
+
+```
+
+runner.addOperatorWithAlias("如果", "if",null);
+runner.addOperatorWithAlias("则", "then",null);
+runner.addOperatorWithAlias("否则", "else",null);
+
+exp = "如果 (如果 1==2 则 false 否则 true) 则 {2+2;} 否则 {20 + 20;}";
+DefaultContext context = new DefaultContext();
+runner.execute(exp,nil,null,false,false,null);
+
+
+//定义一个继承自com.ql.util.express.Operator的操作符
+public class JoinOperator extends Operator{
+ public Object executeInner(Object[] list) throws Exception {
+ Object opdata1 = list[0];
+ Object opdata2 = list[1];
+ if(opdata1 instanceof java.util.List){
+ ((java.util.List)opdata1).add(opdata2);
+ return opdata1;
+ }else{
+ java.util.List result = new java.util.ArrayList();
+ result.add(opdata1);
+ result.add(opdata2);
+ return result;
+ }
+ }
+}
+
+ExpressRunner runner = new ExpressRunner();
+DefaultContext context = new DefaultContext();
+runner.addOperator("join",new JoinOperator());
+Object r = runner.execute("1 join 2 join 3", context, null, false, false);
+System.out.println(r);
+//返回结果 [1, 2, 3]
+
+
+class GroupOperator extends Operator {
+ public GroupOperator(String aName) {
+ this.name= aName;
+ }
+ public Object executeInner(Object[] list)throws Exception {
+ Object result = Integer.valueOf(0);
+ for (int i = 0; i < list.length; i++) {
+ result = OperatorOfNumber.add(result, list[i],false);//根据list[i]类型(string,number等)做加法
+ }
+ return result;
+ }
+}
+
+runner.addFunction("group", new GroupOperator("group"));
+ExpressRunner runner = new ExpressRunner();
+DefaultContext context = new DefaultContext();
+runner.addOperator("join",new JoinOperator());
+Object r = runner.execute("group(1,2,3)", context, null, false, false);
+System.out.println(r);
+//返回结果 6
+
+```
+
+ 3、类的静态方法,对象的方法绑定:addFunctionOfClassMethod+addFunctionOfServiceMethod
+
+```
+
+public class BeanExample {
+ public static String upper(String abc) {
+ return abc.toUpperCase();
+ }
+ public boolean anyContains(String str, String searchStr) {
+
+ char[] s = str.toCharArray();
+ for (char c : s) {
+ if (searchStr.contains(c+"")) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
+
+runner.addFunctionOfClassMethod("取绝对值", Math.class.getName(), "abs",
+ new String[] { "double" }, null);
+runner.addFunctionOfClassMethod("转换为大写", BeanExample.class.getName(),
+ "upper", new String[] { "String" }, null);
+
+runner.addFunctionOfServiceMethod("打印", System.out, "println",new String[] { "String" }, null);
+runner.addFunctionOfServiceMethod("contains", new BeanExample(), "anyContains",
+ new Class[] { String.class, String.class }, null);
+
+String exp = “取绝对值(-100);转换为大写(\"hello world\");打印(\"你好吗?\");contains("helloworld",\"aeiou\")”;
+runner.execute(exp, context, null, false, false);
+
+```
+
+
+ 4、macro 宏定义
+
+```
+runner.addMacro("计算平均成绩", "(语文+数学+英语)/3.0");
+runner.addMacro("是否优秀", "计算平均成绩>90");
+IExpressContext context =new DefaultContext();
+context.put("语文", 88);
+context.put("数学", 99);
+context.put("英语", 95);
+Object result = runner.execute("是否优秀", context, null, false, false);
+System.out.println(r);
+//返回结果true
+
+```
+
+ 5、编译脚本,查询外部需要定义的变量,注意以下脚本int和没有int的区别
+
+```
+String express = "int 平均分 = (语文+数学+英语+综合考试.科目2)/4.0;return 平均分";
+ExpressRunner runner = new ExpressRunner(true,true);
+String[] names = runner.getOutVarNames(express);
+for(String s:names){
+ System.out.println("var : " + s);
+}
+
+//输出结果:
+
+var : 数学
+var : 综合考试
+var : 英语
+var : 语文
+```
+
+6、关于不定参数的使用
+
+```
+ @Test
+ public void testMethodReplace() throws Exception {
+ ExpressRunner runner = new ExpressRunner();
+ IExpressContext expressContext = new DefaultContext();
+ runner.addFunctionOfServiceMethod("getTemplate", this, "getTemplate", new Class[]{Object[].class}, null);
+
+ //(1)默认的不定参数可以使用数组来代替
+ Object r = runner.execute("getTemplate([11,'22',33L,true])", expressContext, null,false, false);
+ System.out.println(r);
+ //(2)像java一样,支持函数动态参数调用,需要打开以下全局开关,否则以下调用会失败
+ DynamicParamsUtil.supportDynamicParams = true;
+ r = runner.execute("getTemplate(11,'22',33L,true)", expressContext, null,false, false);
+ System.out.println(r);
+ }
+ //等价于getTemplate(Object[] params)
+ public Object getTemplate(Object... params) throws Exception{
+ String result = "";
+ for(Object obj:params){
+ result = result+obj+",";
+ }
+ return result;
+ }
+ ```
+
+7、关于集合的快捷写法
+
+```
+ @Test
+ public void testSet() throws Exception {
+ ExpressRunner runner = new ExpressRunner(false,false);
+ DefaultContext context = new DefaultContext();
+ String express = "abc = NewMap(1:1,2:2); return abc.get(1) + abc.get(2);";
+ Object r = runner.execute(express, context, null, false, false);
+ System.out.println(r);
+ express = "abc = NewList(1,2,3); return abc.get(1)+abc.get(2)";
+ r = runner.execute(express, context, null, false, false);
+ System.out.println(r);
+ express = "abc = [1,2,3]; return abc[1]+abc[2];";
+ r = runner.execute(express, context, null, false, false);
+ System.out.println(r);
+ }
+
+```
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e889e2f050f71717f51a170904430b5b129e16e7
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,93 @@
+
+
+
+ 4.0.0
+ com.taobao.util
+ taobao-express
+ jar
+ 3.0.18
+ taobao-express
+
+
+
+ commons-beanutils
+ commons-beanutils
+ 1.8.2
+
+
+ log4j
+ log4j
+ 1.2.16
+
+
+ commons-logging
+ commons-logging
+ 1.1.1
+
+
+ commons-lang
+ commons-lang
+ 2.4
+
+
+ junit
+ junit
+ 4.4
+ test
+
+
+ org.unitils
+ unitils
+ 2.3
+ test
+
+
+ org.springframework
+ spring
+ 2.5.6
+ test
+
+
+
+
+
+ releases
+ http://mvnrepo.alibaba-inc.com/mvn/releases
+
+
+ snapshots
+ http://mvnrepo.alibaba-inc.com/mvn/snapshots
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ 1.6
+
+
+
+ maven-source-plugin
+ 2.1
+
+ true
+
+
+
+ compile
+
+ jar
+
+
+
+
+
+
+
+
diff --git a/src/main/java/com/ql/util/express/ArraySwap.java b/src/main/java/com/ql/util/express/ArraySwap.java
new file mode 100644
index 0000000000000000000000000000000000000000..94af570fea77c853c1f3b312d3a436edc5c375ab
--- /dev/null
+++ b/src/main/java/com/ql/util/express/ArraySwap.java
@@ -0,0 +1,17 @@
+package com.ql.util.express;
+
+public final class ArraySwap {
+ OperateData[] arrays;
+ int start;
+ public int length;
+
+ public void swap(OperateData[] aArrays,int aStart ,int aLength){
+ this.arrays = aArrays;
+ this.start = aStart;
+ this.length = aLength;
+ }
+ public OperateData get(int i){
+ return this.arrays[i+start];
+ }
+
+}
diff --git a/src/main/java/com/ql/util/express/CacheObject.java b/src/main/java/com/ql/util/express/CacheObject.java
new file mode 100644
index 0000000000000000000000000000000000000000..68dcfc499cb508063b541c30552a1e7bfd49b55d
--- /dev/null
+++ b/src/main/java/com/ql/util/express/CacheObject.java
@@ -0,0 +1,47 @@
+package com.ql.util.express;
+
+import java.io.Serializable;
+
+/**
+ * 简单的缓存对象
+ * @author tianqiao
+ *
+ */
+public class CacheObject implements Serializable{
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -145121001676214513L;
+
+ private String expressName;
+
+ private String text;
+
+ private InstructionSet instructionSet;
+
+ public String getExpressName() {
+ return expressName;
+ }
+
+ public void setExpressName(String name) {
+ this.expressName = name;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public void setText(String text) {
+ this.text = text;
+ }
+
+ public InstructionSet getInstructionSet() {
+ return instructionSet;
+ }
+
+ public void setInstructionSet(InstructionSet instructionSet) {
+ this.instructionSet = instructionSet;
+ }
+
+}
diff --git a/src/main/java/com/ql/util/express/CallResult.java b/src/main/java/com/ql/util/express/CallResult.java
new file mode 100644
index 0000000000000000000000000000000000000000..03e224d8f0908f415897267d6b14f208098c607c
--- /dev/null
+++ b/src/main/java/com/ql/util/express/CallResult.java
@@ -0,0 +1,25 @@
+package com.ql.util.express;
+
+public class CallResult{
+ private Object returnValue;
+ private boolean isExit;
+ public CallResult(Object aReturnValue,boolean aIsExit){
+ this.initial(aReturnValue, aIsExit);
+ }
+ public void initial(Object aReturnValue,boolean aIsExit){
+ this.returnValue = aReturnValue;
+ this.isExit = aIsExit;
+ }
+ public void clear(){
+ this.returnValue = null;
+ this.isExit = false;
+ }
+ public Object getReturnValue() {
+ return returnValue;
+ }
+ public boolean isExit() {
+ return isExit;
+ }
+
+}
+
diff --git a/src/main/java/com/ql/util/express/DefaultContext.java b/src/main/java/com/ql/util/express/DefaultContext.java
new file mode 100644
index 0000000000000000000000000000000000000000..c0e75acd81caf2a76e47ca74fbfb479edbc397c6
--- /dev/null
+++ b/src/main/java/com/ql/util/express/DefaultContext.java
@@ -0,0 +1,8 @@
+package com.ql.util.express;
+
+import java.util.HashMap;
+
+
+@SuppressWarnings("serial")
+public class DefaultContext extends HashMap implements IExpressContext {
+}
diff --git a/src/main/java/com/ql/util/express/DefaultExpressResourceLoader.java b/src/main/java/com/ql/util/express/DefaultExpressResourceLoader.java
new file mode 100644
index 0000000000000000000000000000000000000000..57f23ad23c3ad9d5eac50f8c0387d0769c6e6c6d
--- /dev/null
+++ b/src/main/java/com/ql/util/express/DefaultExpressResourceLoader.java
@@ -0,0 +1,25 @@
+package com.ql.util.express;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+public class DefaultExpressResourceLoader implements IExpressResourceLoader {
+ public String loadExpress(String expressName) throws Exception {
+ expressName = expressName.replace('.', '/') + ".ql";
+ InputStream in = Thread.currentThread().getContextClassLoader()
+ .getResourceAsStream(expressName);
+ if (in == null) {
+ throw new Exception("不能找到表达式文件:" + expressName);
+ }
+ BufferedReader reader = new BufferedReader(new InputStreamReader(in));
+ StringBuilder builder = new StringBuilder();
+ String tmpStr = null;
+ while ((tmpStr = reader.readLine()) != null) {
+ builder.append(tmpStr).append("\n");
+ }
+ reader.close();
+ in.close();
+ return builder.toString();
+ }
+}
diff --git a/src/main/java/com/ql/util/express/DynamicParamsUtil.java b/src/main/java/com/ql/util/express/DynamicParamsUtil.java
new file mode 100644
index 0000000000000000000000000000000000000000..43952ca3e2bfb2fcccb6b582da680ae4e6c5e6e2
--- /dev/null
+++ b/src/main/java/com/ql/util/express/DynamicParamsUtil.java
@@ -0,0 +1,79 @@
+package com.ql.util.express;
+
+import java.lang.reflect.Array;
+
+/**
+ * Created by tianqiao on 16/9/12.
+ */
+public class DynamicParamsUtil {
+
+ public static boolean supportDynamicParams = false;
+
+ public static Object[] transferDynamicParams(InstructionSetContext context, ArraySwap list, Class>[] delaredParamsClasses,boolean maybeDynamicParams) throws Exception {
+
+ Object[] params = null;
+ //参数定义不符合动态参数形式 || 用户自定义不支持 || 用户传入的参数不符合
+ if(!maybeDynamicParams || !supportDynamicParams || !maybeDynamicParams(context,list,delaredParamsClasses)){
+ if(delaredParamsClasses.length != list.length){
+ throw new Exception("定义的参数长度与运行期传入的参数长度不一致");
+ }
+ params = new Object[list.length];
+ for (int i = 0; i < list.length; i++) {
+ params[i] = list.get(i).getObject(context);
+ }
+ return params;
+ }
+
+ //支持不定参数的使用 function(arg1,arg2,arg3...)
+ //list -> parameres[]
+ // arg1,arg2 -> arg1,arg2,[]
+ // arg1,arg2,arg3,arg4,arg5 -> arg1,arg2,[arg3,arg4,arg5]
+ int paramLength = delaredParamsClasses.length;
+ int beforeCount = paramLength-1;
+ int paramsCount = list.length - beforeCount;
+
+ if(beforeCount>=0 && ((Class>)(delaredParamsClasses[beforeCount])).isArray() && paramsCount>=0){
+ Class>componentType = delaredParamsClasses[beforeCount].getComponentType();
+ params = new Object[beforeCount+1];
+ Object[] lastParameres = (Object[]) Array.newInstance(componentType,paramsCount);
+ params[beforeCount] = lastParameres;
+ for (int i = 0; i < list.length; i++) {
+ if(i[] delaredParamsClasses)
+ {
+ int length = delaredParamsClasses.length;
+ if(length>0 && delaredParamsClasses[length-1].isArray())
+ {
+ return true;
+ }
+ return false;
+ }
+
+ private static boolean maybeDynamicParams(InstructionSetContext context, ArraySwap list, Class>[] delaredParamsClasses) throws Exception {
+
+ //长度不一致,有可能
+ if(delaredParamsClasses.length != list.length) {
+ return true;
+ }
+ //长度一致的不定参数:不定参数的数组,只输入了一个参数并且为array,有可能
+ int length = list.length;
+ Object lastParam = list.get(length-1).getObject(context);
+ if(lastParam!=null && !lastParam.getClass().isArray())
+ {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/com/ql/util/express/ExportItem.java b/src/main/java/com/ql/util/express/ExportItem.java
new file mode 100644
index 0000000000000000000000000000000000000000..acfc3d9e670994394cd2e70c3646b1fe4f9634d8
--- /dev/null
+++ b/src/main/java/com/ql/util/express/ExportItem.java
@@ -0,0 +1,60 @@
+package com.ql.util.express;
+
+import java.io.Serializable;
+
+/**
+ * 输出给其它指令共享使用的对象
+ * @author xuannan
+ *
+ */
+public class ExportItem implements Serializable{
+ private static final long serialVersionUID = 5440012774123494760L;
+ public static String TYPE_ALIAS ="alias";
+ public static String TYPE_DEF ="def";
+ public static String TYPE_FUNCTION ="function";
+ public static String TYPE_MACRO ="macro";
+ String globeName;
+ String name;
+ String type;//def,alias
+ String desc;//类名或者别名
+ public ExportItem(String aName,String aType,String aDesc){
+ this.globeName = aName;
+ this.name = aName;
+ this.type =aType;
+ this.desc = aDesc;
+ }
+ public ExportItem(String aGlobeName,String aName,String aType,String aDesc){
+ this.globeName = aGlobeName;
+ this.name = aName;
+ this.type =aType;
+ this.desc = aDesc;
+ }
+ public String toString(){
+ return this.globeName + "["+ this.type +":" + this.name +" " + this.desc + "]";
+ }
+ public String getGlobeName() {
+ return globeName;
+ }
+ public void setGlobeName(String globeName) {
+ this.globeName = globeName;
+ }
+ public String getName() {
+ return name;
+ }
+ public void setName(String name) {
+ this.name = name;
+ }
+ public String getType() {
+ return type;
+ }
+ public void setType(String type) {
+ this.type = type;
+ }
+ public String getDesc() {
+ return desc;
+ }
+ public void setDesc(String desc) {
+ this.desc = desc;
+ }
+
+}
diff --git a/src/main/java/com/ql/util/express/ExpressClassLoader.java b/src/main/java/com/ql/util/express/ExpressClassLoader.java
new file mode 100644
index 0000000000000000000000000000000000000000..483140359b0332ed5ea124d7e2ffa8fe098774a0
--- /dev/null
+++ b/src/main/java/com/ql/util/express/ExpressClassLoader.java
@@ -0,0 +1,91 @@
+package com.ql.util.express;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+
+public class ExpressClassLoader extends ClassLoader {
+ public ExpressClassLoader(ClassLoader parent){
+ super(parent);
+ }
+ public Class> loadClass(String name, byte[] code) {
+ return this.defineClass(name, code, 0, code.length);
+ }
+
+ public synchronized Class> loadClass(String name, boolean resolve)
+ throws ClassNotFoundException {
+ //System.out.print("开始查找 类" + name + "。。。。。。。。。。。");
+ Class> clasz = findLoadedClass(this, name);
+ if (clasz != null) {
+ //System.out.println(clasz.getClassLoader());
+ return clasz;
+ }
+ if (clasz == null) {
+ clasz = parentLoadClass(this, name);
+ }
+ if (clasz == null && name.startsWith("[")) { // 进行数组处理
+ int index = name.indexOf("L");
+ String str = name.substring(0, index);
+ String componentClassName = name.substring(index + 1,
+ name.length() - 1);
+ int[] dimes = new int[str.length()];
+ for (int i = 0; i < dimes.length; i++) {
+ dimes[i] = 0;
+ }
+ try {
+ Class> componentType = this.loadClass(componentClassName);
+ clasz = Array.newInstance(componentType, dimes).getClass();
+ } catch (Exception e) {
+ // 不错处理
+ }
+ }
+
+ if (clasz == null)
+ throw new ClassNotFoundException(name);
+ return clasz;
+ }
+
+ public static Class> findLoadedClass(ClassLoader loader, String name)
+ throws ClassNotFoundException {
+ Method m = null;
+ try {
+ m = ClassLoader.class.getDeclaredMethod("findLoadedClass",
+ new Class[] { String.class });
+ m.setAccessible(true);
+ Class> result = (Class>) m.invoke(loader, new Object[] { name });
+ if (result == null) {
+ result = (Class>) m.invoke(loader.getClass().getClassLoader(),
+ new Object[] { name });
+ }
+ if (result == null) {
+ result = (Class>) m.invoke(Thread.currentThread()
+ .getContextClassLoader(), new Object[] { name });
+ }
+ return result;
+ } catch (Exception ex) {
+ throw new ClassNotFoundException(ex.getMessage());
+ } finally {
+ if (m != null) {
+ m.setAccessible(false);
+ }
+ }
+ }
+
+ public static Class> parentLoadClass(ClassLoader loader, String name)
+ throws ClassNotFoundException {
+ // 如果存在这个类,则直接返回
+ Class> clasz = null;
+ if (clasz == null) {
+ try {
+ clasz = loader.getClass().getClassLoader().loadClass(name);
+ } catch (Throwable e) {
+ }
+ }
+ if (clasz == null)
+ try {
+ clasz = Thread.currentThread().getContextClassLoader()
+ .loadClass(name);
+ } catch (Throwable e) {
+ }
+ return clasz;
+ }
+}
diff --git a/src/main/java/com/ql/util/express/ExpressLoader.java b/src/main/java/com/ql/util/express/ExpressLoader.java
new file mode 100644
index 0000000000000000000000000000000000000000..fc7200b70e03757ead0b8daafa6906cc1f652a6e
--- /dev/null
+++ b/src/main/java/com/ql/util/express/ExpressLoader.java
@@ -0,0 +1,77 @@
+package com.ql.util.express;
+
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.concurrent.ConcurrentHashMap;
+
+import com.ql.util.express.instruction.FunctionInstructionSet;
+
+
+/**
+ * 表达式装载器
+ *
+ * @author xuannan
+ *
+ */
+public class ExpressLoader {
+ private ConcurrentHashMap expressInstructionSetCache = new ConcurrentHashMap();
+ ExpressRunner creator;
+ public ExpressLoader(ExpressRunner aCreator){
+ this.creator = aCreator;
+ }
+ public InstructionSet loadExpress(String expressName)
+ throws Exception {
+ return parseInstructionSet(expressName,this.creator.getExpressResourceLoader().loadExpress(expressName));
+ }
+
+ public void addInstructionSet(String expressName, InstructionSet set)
+ throws Exception {
+ synchronized (expressInstructionSetCache) {
+ if (expressInstructionSetCache.containsKey(expressName)) {
+ throw new Exception("表达式定义重复:" + expressName);
+ }
+ expressInstructionSetCache.put(expressName, set);
+ }
+ }
+
+ public InstructionSet parseInstructionSet(String expressName,
+ String expressString) throws Exception {
+ InstructionSet parseResult = null;
+ if (expressInstructionSetCache.containsKey(expressName)) {
+ throw new Exception("表达式定义重复:" + expressName);
+ }
+ synchronized (expressInstructionSetCache) {
+ parseResult = this.creator.parseInstructionSet(expressString);
+ parseResult.setName(expressName);
+ parseResult.setGlobeName(expressName);
+ // 需要将函数和宏定义都提取出来
+ for (FunctionInstructionSet item : parseResult
+ .getFunctionInstructionSets()) {
+ this.addInstructionSet(item.name, item.instructionSet);
+ item.instructionSet.setName(item.name);
+ item.instructionSet.setGlobeName(expressName+ "." + item.name);
+ }
+ if(parseResult.hasMain()){
+ this.addInstructionSet(expressName, parseResult);
+ }
+ }
+ return parseResult;
+ }
+ public void clear(){
+ this.expressInstructionSetCache.clear();
+ }
+ public InstructionSet getInstructionSet(String expressName) {
+ return expressInstructionSetCache.get(expressName);
+ }
+ public ExportItem[] getExportInfo(){
+ Map result = new TreeMap();
+ for(InstructionSet item:expressInstructionSetCache.values()){
+ for(ExportItem var:item.getExportDef()){
+ var.setGlobeName(item.getGlobeName() + "." + var.name);
+ result.put(var.getGlobeName(),var);
+ }
+ result.put(item.getGlobeName(),new ExportItem(item.getGlobeName(), item.getName(),item.getType(),item.toString()));
+ }
+ return (ExportItem[])result.values().toArray(new ExportItem[0]);
+ }
+}
diff --git a/src/main/java/com/ql/util/express/ExpressRemoteCacheRunner.java b/src/main/java/com/ql/util/express/ExpressRemoteCacheRunner.java
new file mode 100644
index 0000000000000000000000000000000000000000..f2190f9ed7d841c4400ecb83b53920223a745e71
--- /dev/null
+++ b/src/main/java/com/ql/util/express/ExpressRemoteCacheRunner.java
@@ -0,0 +1,64 @@
+package com.ql.util.express;
+
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+
+/**
+ * 远程缓存对象
+ * @author tianqiao
+ *
+ */
+public abstract class ExpressRemoteCacheRunner {
+
+
+
+ public void loadCache(String expressName,String text){
+ InstructionSet instructionSet;
+ try {
+ instructionSet = getExpressRunner().parseInstructionSet(text);
+ CacheObject cache = new CacheObject();
+ cache.setExpressName(expressName);
+ cache.setText(text);
+ cache.setInstructionSet(instructionSet);
+ this.putCache(expressName, cache);
+ } catch (Exception e) {
+ throw new RuntimeException("解析指令并缓存过程出现错误.",e);
+ }
+ }
+
+
+ public Object execute(String name,IExpressContext context, List errorList,
+ boolean isTrace,boolean isCatchException, Log aLog){
+ try {
+ CacheObject cache = (CacheObject) this.getCache(name);
+ if(cache==null){
+ throw new RuntimeException("未获取到缓存对象.");
+ }
+ return getExpressRunner().execute(cache.getInstructionSet(), context, errorList, isTrace, isCatchException, aLog);
+ } catch (Exception e) {
+ throw new RuntimeException("获取缓存信息,并且执行指令集出现错误.",e);
+ }
+ }
+
+ /**
+ * 获取执行器ExpressRunner
+ * @return
+ */
+ public abstract ExpressRunner getExpressRunner();
+ /**
+ * 获取缓存对象
+ * @param key
+ * @return
+ */
+ public abstract Object getCache(String key);
+ /**
+ * 放置缓存的对象
+ * @param key
+ * @param object
+ */
+ public abstract void putCache(String key,Object object );
+
+}
+
+
diff --git a/src/main/java/com/ql/util/express/ExpressRunner.java b/src/main/java/com/ql/util/express/ExpressRunner.java
new file mode 100644
index 0000000000000000000000000000000000000000..a23b6f645ff2ea02cf9ce9d76970c1e71295c1a0
--- /dev/null
+++ b/src/main/java/com/ql/util/express/ExpressRunner.java
@@ -0,0 +1,657 @@
+package com.ql.util.express;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+import com.ql.util.express.parse.*;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import com.ql.util.express.instruction.ForRelBreakContinue;
+import com.ql.util.express.instruction.IOperateDataCache;
+import com.ql.util.express.instruction.InstructionFactory;
+import com.ql.util.express.instruction.OperateDataCacheImpl;
+import com.ql.util.express.instruction.op.OperatorBase;
+import com.ql.util.express.instruction.op.OperatorFactory;
+import com.ql.util.express.instruction.op.OperatorMinMax;
+import com.ql.util.express.instruction.op.OperatorPrint;
+import com.ql.util.express.instruction.op.OperatorPrintln;
+import com.ql.util.express.instruction.op.OperatorRound;
+import com.ql.util.express.instruction.op.OperatorSelfDefineClassFunction;
+import com.ql.util.express.instruction.op.OperatorSelfDefineServiceFunction;
+
+/**
+ * 语法分析和计算的入口类
+ * @author xuannan
+ *
+ */
+public class ExpressRunner {
+
+ private static final Log log = LogFactory.getLog(ExpressRunner.class);
+ private static final String GLOBAL_DEFINE_NAME="全局定义";
+ /**
+ * 是否输出所有的跟踪信息,同时还需要log级别是DEBUG级别
+ */
+ private boolean isTrace = false;
+
+ /**
+ * 是否使用逻辑短路特性增强质量的效率
+ */
+ private boolean isShortCircuit = true;
+
+ /**
+ * 是否需要高精度计算
+ */
+ private boolean isPrecise = false;
+
+ /**
+ * 一段文本对应的指令集的缓存
+ */
+ private Map expressInstructionSetCache = new HashMap();
+
+ private ExpressLoader loader;
+ private IExpressResourceLoader expressResourceLoader;
+ /**
+ * 语法定义的管理器
+ */
+ private NodeTypeManager manager;
+ /**
+ * 操作符的管理器
+ */
+ private OperatorFactory operatorManager;
+ /**
+ * 语法分析器
+ */
+ private ExpressParse parse ;
+
+ /**
+ * 缺省的Class查找的包管理器
+ */
+ ExpressPackage rootExpressPackage = new ExpressPackage(null);
+
+ public AppendingClassMethodManager getAppendingClassMethodManager() {
+ return appendingClassMethodManager;
+ }
+
+ private AppendingClassMethodManager appendingClassMethodManager;
+
+ public AppendingClassFieldManager getAppendingClassFieldManager() {
+ return appendingClassFieldManager;
+ }
+
+ private AppendingClassFieldManager appendingClassFieldManager;
+
+ private ThreadLocal m_OperateDataObjectCache = new ThreadLocal(){
+ protected IOperateDataCache initialValue() {
+ return new OperateDataCacheImpl(30);
+ }
+ };
+ public IOperateDataCache getOperateDataCache(){
+ return this.m_OperateDataObjectCache.get();
+ }
+
+ public ExpressRunner(){
+ this(false,false);
+ }
+ /**
+ *
+ * @param aIsPrecise 是否需要高精度计算支持
+ * @param aIstrace 是否跟踪执行指令的过程
+ */
+ public ExpressRunner(boolean aIsPrecise,boolean aIstrace){
+ this(aIsPrecise,aIstrace,new DefaultExpressResourceLoader(),null);
+ }
+ public ExpressRunner(boolean aIsPrecise,boolean aIstrace,NodeTypeManager aManager){
+ this(aIsPrecise,aIstrace,new DefaultExpressResourceLoader(),aManager);
+ }
+ /**
+ *
+ * @param aIsPrecise 是否需要高精度计算支持
+ * @param aIstrace 是否跟踪执行指令的过程
+ * @param aExpressResourceLoader 表达式的资源装载器
+ */
+ public ExpressRunner(boolean aIsPrecise,boolean aIstrace,IExpressResourceLoader aExpressResourceLoader,NodeTypeManager aManager){
+ this.isTrace = aIstrace;
+ this.isPrecise = aIsPrecise;
+ this.expressResourceLoader = aExpressResourceLoader;
+ if(aManager == null){
+ manager = new NodeTypeManager();
+ }else{
+ manager = aManager;
+ }
+ this.operatorManager = new OperatorFactory(this.isPrecise);
+ this.loader = new ExpressLoader(this);
+ this.parse = new ExpressParse(manager,this.expressResourceLoader,this.isPrecise);
+ rootExpressPackage.addPackage("java.lang");
+ rootExpressPackage.addPackage("java.util");
+ this.addSystemFunctions();
+ }
+ public void addSystemFunctions(){
+ this.addFunction("max", new OperatorMinMax("max"));
+ this.addFunction("min", new OperatorMinMax("min"));
+ this.addFunction("round", new OperatorRound("round"));
+ this.addFunction("print", new OperatorPrint("print"));
+ this.addFunction("println", new OperatorPrintln("println"));
+ }
+
+ /**
+ * 获取语法定义的管理器
+ * @return
+ */
+ public NodeTypeManager getNodeTypeManager(){
+ return this.manager;
+ }
+ /**
+ * 获取操作符号管理器
+ * @return
+ */
+ public OperatorFactory getOperatorFactory(){
+ return this.operatorManager;
+ }
+ public IExpressResourceLoader getExpressResourceLoader(){
+ return this.expressResourceLoader;
+ }
+ /**
+ * 添加宏定义 例如: macro 玄难 { abc(userinfo.userId);}
+ * @param macroName:玄难
+ * @param express :abc(userinfo.userId);
+ * @throws Exception
+ */
+ public void addMacro(String macroName,String express) throws Exception{
+ String macroExpress = "macro " + macroName +" {" + express + "}";
+ this.loader.parseInstructionSet(GLOBAL_DEFINE_NAME,macroExpress);
+ }
+
+ /**
+ * 装载表达式,但不执行,例如一些宏定义,或者自定义函数
+ * @param groupName
+ * @param express
+ * @throws Exception
+ */
+ public void loadMutilExpress(String groupName,String express) throws Exception{
+ if(groupName == null || groupName.trim().length() ==0){
+ groupName = GLOBAL_DEFINE_NAME;
+ }
+ this.loader.parseInstructionSet(groupName,express);
+ }
+ /**
+ * 装载文件中定义的Express
+ * @param expressName
+ * @throws Exception
+ */
+ public void loadExpress(String expressName) throws Exception {
+ this.loader.loadExpress(expressName);
+ }
+ /**
+ * 添加函数定义
+ * @param name 函数名称
+ * @param op 对应的操作实现类
+ */
+ public void addFunction(String name, OperatorBase op) {
+ this.operatorManager.addOperator(name, op);
+ this.manager.addFunctionName(name);
+ };
+
+ /**
+ * 添加函数定义扩展类的方法
+ * @param name
+ * @param bindingClass
+ * @param op
+ */
+ public void addFunctionAndClassMethod(String name,Class>bindingClass, OperatorBase op) {
+ this.addFunction(name,op);
+ this.addClassMethod(name,bindingClass,op);
+
+ };
+
+ /**
+ * 添加类的方法
+ * @param field
+ * @param bindingClass
+ * @param op
+ */
+ public void addClassField(String field,Class>bindingClass,Operator op)
+ {
+ this.addClassField(field,bindingClass,Object.class,op);
+ }
+
+ /**
+ * 添加类的方法
+ * @param field
+ * @param bindingClass
+ * @param returnType
+ * @param op
+ */
+ public void addClassField(String field,Class>bindingClass,Class>returnType,Operator op)
+ {
+ if(this.appendingClassFieldManager==null){
+ this.appendingClassFieldManager = new AppendingClassFieldManager();
+ }
+ this.appendingClassFieldManager.addAppendingField(field, bindingClass,returnType,op);
+ }
+
+ /**
+ * 添加类的方法
+ * @param name
+ * @param bindingClass
+ * @param op
+ */
+ public void addClassMethod(String name,Class>bindingClass,OperatorBase op)
+ {
+ if(this.appendingClassMethodManager==null){
+ this.appendingClassMethodManager = new AppendingClassMethodManager();
+ }
+ this.appendingClassMethodManager.addAppendingMethod(name, bindingClass, op);
+ }
+ /**
+ * 获取函数定义,通过函数定义可以拿到参数的说明信息
+ * @param name 函数名称
+ * @return
+ */
+ public OperatorBase getFunciton(String name){
+ return this.operatorManager.getOperator(name);
+ }
+ /**
+ * 添加一个类的函数定义,例如:Math.abs(double) 映射为表达式中的 "取绝对值(-5.0)"
+ * @param name 函数名称
+ * @param aClassName 类名称
+ * @param aFunctionName 类中的方法名称
+ * @param aParameterClassTypes 方法的参数类型名称
+ * @param errorInfo 如果函数执行的结果是false,需要输出的错误信息
+ * @throws Exception
+ */
+ public void addFunctionOfClassMethod(String name, String aClassName,
+ String aFunctionName, Class>[] aParameterClassTypes,
+ String errorInfo) throws Exception {
+ this.addFunction(name, new OperatorSelfDefineClassFunction(name,
+ aClassName, aFunctionName, aParameterClassTypes,null,null, errorInfo));
+
+ }
+ /**
+ * 添加一个类的函数定义,例如:Math.abs(double) 映射为表达式中的 "取绝对值(-5.0)"
+ * @param name 函数名称
+ * @param aClassName 类名称
+ * @param aFunctionName 类中的方法名称
+ * @param aParameterClassTypes 方法的参数类型名称
+ * @param aParameterDesc 方法的参数说明
+ * @param aParameterAnnotation 方法的参数注解
+ * @param errorInfo 如果函数执行的结果是false,需要输出的错误信息
+ * @throws Exception
+ */
+ public void addFunctionOfClassMethod(String name, String aClassName,
+ String aFunctionName, Class>[] aParameterClassTypes,
+ String[] aParameterDesc,String[] aParameterAnnotation,
+ String errorInfo) throws Exception {
+ this.addFunction(name, new OperatorSelfDefineClassFunction(name,
+ aClassName, aFunctionName, aParameterClassTypes,aParameterDesc,aParameterAnnotation, errorInfo));
+
+ }
+ /**
+ * 添加一个类的函数定义,例如:Math.abs(double) 映射为表达式中的 "取绝对值(-5.0)"
+ * @param name 函数名称
+ * @param aClassName 类名称
+ * @param aFunctionName 类中的方法名称
+ * @param aParameterTypes 方法的参数类型名称
+ * @param errorInfo 如果函数执行的结果是false,需要输出的错误信息
+ * @throws Exception
+ */
+ public void addFunctionOfClassMethod(String name, String aClassName,
+ String aFunctionName, String[] aParameterTypes, String errorInfo)
+ throws Exception {
+ this.addFunction(name, new OperatorSelfDefineClassFunction(name,
+ aClassName, aFunctionName, aParameterTypes, null,null,errorInfo));
+ }
+ /**
+ * 添加一个类的函数定义,例如:Math.abs(double) 映射为表达式中的 "取绝对值(-5.0)"
+ * @param name 函数名称
+ * @param aClassName 类名称
+ * @param aFunctionName 类中的方法名称
+ * @param aParameterTypes 方法的参数类型名称
+ * @param aParameterDesc 方法的参数说明
+ * @param aParameterAnnotation 方法的参数注解
+ * @param errorInfo 如果函数执行的结果是false,需要输出的错误信息
+ * @throws Exception
+ */
+ public void addFunctionOfClassMethod(String name, String aClassName,
+ String aFunctionName, String[] aParameterTypes,
+ String[] aParameterDesc,String[] aParameterAnnotation,
+ String errorInfo)
+ throws Exception {
+ this.addFunction(name, new OperatorSelfDefineClassFunction(name,
+ aClassName, aFunctionName, aParameterTypes, aParameterDesc,aParameterAnnotation,errorInfo));
+
+ }
+ /**
+ * 用于将一个用户自己定义的对象(例如Spring对象)方法转换为一个表达式计算的函数
+ * @param name
+ * @param aServiceObject
+ * @param aFunctionName
+ * @param aParameterClassTypes
+ * @param errorInfo
+ * @throws Exception
+ */
+ public void addFunctionOfServiceMethod(String name, Object aServiceObject,
+ String aFunctionName, Class>[] aParameterClassTypes,
+ String errorInfo) throws Exception {
+ this.addFunction(name, new OperatorSelfDefineServiceFunction(name,
+ aServiceObject, aFunctionName, aParameterClassTypes,null,null, errorInfo));
+
+ }
+ /**
+ * 用于将一个用户自己定义的对象(例如Spring对象)方法转换为一个表达式计算的函数
+ * @param name
+ * @param aServiceObject
+ * @param aFunctionName
+ * @param aParameterClassTypes
+ * @param aParameterDesc 方法的参数说明
+ * @param aParameterAnnotation 方法的参数注解
+ * @param errorInfo
+ * @throws Exception
+ */
+ public void addFunctionOfServiceMethod(String name, Object aServiceObject,
+ String aFunctionName, Class>[] aParameterClassTypes,
+ String[] aParameterDesc,String[] aParameterAnnotation,
+ String errorInfo) throws Exception {
+ this.addFunction(name, new OperatorSelfDefineServiceFunction(name,
+ aServiceObject, aFunctionName, aParameterClassTypes,aParameterDesc,aParameterAnnotation, errorInfo));
+
+ }
+ /**
+ * 用于将一个用户自己定义的对象(例如Spring对象)方法转换为一个表达式计算的函数
+ * @param name
+ * @param aServiceObject
+ * @param aFunctionName
+ * @param aParameterTypes
+ * @param errorInfo
+ * @throws Exception
+ */
+ public void addFunctionOfServiceMethod(String name, Object aServiceObject,
+ String aFunctionName, String[] aParameterTypes, String errorInfo)
+ throws Exception {
+ this.addFunction(name, new OperatorSelfDefineServiceFunction(name,
+ aServiceObject, aFunctionName, aParameterTypes,null,null, errorInfo));
+
+ }
+ public void addFunctionOfServiceMethod(String name, Object aServiceObject,
+ String aFunctionName, String[] aParameterTypes,
+ String[] aParameterDesc,String[] aParameterAnnotation,
+ String errorInfo)
+ throws Exception {
+ this.addFunction(name, new OperatorSelfDefineServiceFunction(name,
+ aServiceObject, aFunctionName, aParameterTypes,aParameterDesc,aParameterAnnotation, errorInfo));
+
+ }
+ /**
+ * 添加操作符号,此操作符号的优先级与 "*"相同,语法形式也是 data name data
+ * @param name
+ * @param op
+ * @throws Exception
+ */
+ public void addOperator(String name,Operator op) throws Exception {
+ this.addOperator(name, "*", op);
+ }
+ /**
+ * 添加操作符号,此操作符号与给定的参照操作符号在优先级别和语法形式上一致
+ * @param name 操作符号名称
+ * @param aRefOpername 参照的操作符号,例如 "+","--"等
+ * @param op
+ * @throws Exception
+ */
+ public void addOperator(String name,String aRefOpername,Operator op) throws Exception {
+ this.manager.addOperatorWithLevelOfReference(name, aRefOpername);
+ this.operatorManager.addOperator(name, op);
+ }
+
+ /**
+ * 添加操作符和关键字的别名,同时对操作符可以指定错误信息。
+ * 例如:addOperatorWithAlias("加","+",null)
+ * @param keyWordName
+ * @param realKeyWordName
+ * @param errorInfo
+ * @throws Exception
+ */
+ public void addOperatorWithAlias(String keyWordName, String realKeyWordName,
+ String errorInfo) throws Exception {
+ if(errorInfo != null && errorInfo.trim().length() == 0){
+ errorInfo = null;
+ }
+ //添加函数别名
+ if(this.manager.isFunction(realKeyWordName)){
+ this.manager.addFunctionName(keyWordName);
+ this.operatorManager.addOperatorWithAlias(keyWordName, realKeyWordName, errorInfo);
+ return;
+ }
+ NodeType realNodeType = this.manager.findNodeType(realKeyWordName);
+ if(realNodeType == null){
+ throw new Exception("关键字:" + realKeyWordName +"不存在");
+ }
+ boolean isExist = this.operatorManager.isExistOperator(realNodeType.getName());
+ if(isExist == false && errorInfo != null){
+ throw new Exception("关键字:" + realKeyWordName +"是通过指令来实现的,不能设置错误的提示信息,errorInfo 必须是 null");
+ }
+ if(isExist == false || errorInfo == null){
+ //不需要新增操作符号,只需要建立一个关键子即可
+ this.manager.addOperatorWithRealNodeType(keyWordName, realNodeType.getName());
+ }else{
+ this.manager.addOperatorWithLevelOfReference(keyWordName, realNodeType.getName());
+ this.operatorManager.addOperatorWithAlias(keyWordName, realNodeType.getName(), errorInfo);
+ }
+ }
+ /**
+ * 替换操作符处理
+ * @param name
+ */
+ public OperatorBase replaceOperator(String name,OperatorBase op){
+ return this.operatorManager.replaceOperator(name, op);
+ }
+
+ public ExpressPackage getRootExpressPackage(){
+ return this.rootExpressPackage;
+ }
+ /**
+ * 清除缓存
+ */
+ public void clearExpressCache() {
+ this.expressInstructionSetCache.clear();
+ }
+ /**
+ * 根据表达式的名称进行执行
+ * @param name
+ * @param context
+ * @param errorList
+ * @param isTrace
+ * @param isCatchException
+ * @param aLog
+ * @return
+ * @throws Exception
+ */
+ public Object executeByExpressName(String name,IExpressContext context, List errorList,
+ boolean isTrace,boolean isCatchException, Log aLog) throws Exception {
+ return InstructionSetRunner.executeOuter(this,this.loader.getInstructionSet(name),this.loader,context, errorList,
+ isTrace,isCatchException,aLog,false);
+
+ }
+
+ /**
+ * 执行指令集(兼容老接口,请不要自己管理指令缓存,直接使用execute(InstructionSet instructionSets,....... )
+ * 清理缓存可以使用clearExpressCache()函数
+ * @param instructionSets
+ * @param context
+ * @param errorList
+ * @param isTrace
+ * @param isCatchException
+ * @param aLog
+ * @return
+ * @throws Exception
+ */
+ @Deprecated
+ public Object execute(InstructionSet[] instructionSets,IExpressContext context, List errorList,
+ boolean isTrace,boolean isCatchException, Log aLog) throws Exception {
+ return InstructionSetRunner.executeOuter(this,instructionSets[0],this.loader,context, errorList,
+ isTrace,isCatchException,aLog,false);
+ }
+
+ /**
+ * 执行指令集
+ * @param instructionSets
+ * @param context
+ * @param errorList
+ * @param isTrace
+ * @param isCatchException
+ * @param aLog
+ * @return
+ * @throws Exception
+ */
+ public Object execute(InstructionSet instructionSets,IExpressContext context, List errorList,
+ boolean isTrace,boolean isCatchException, Log aLog) throws Exception {
+ return InstructionSetRunner.executeOuter(this,instructionSets,this.loader,context, errorList,
+ isTrace,isCatchException,aLog,false);
+ }
+/**
+ * 执行一段文本
+ * @param expressString 程序文本
+ * @param context 执行上下文
+ * @param errorList 输出的错误信息List
+ * @param isCache 是否使用Cache中的指令集
+ * @param isTrace 是否输出详细的执行指令信息
+ * @return
+ * @throws Exception
+ */
+ public Object execute(String expressString, IExpressContext context,
+ List errorList, boolean isCache, boolean isTrace) throws Exception {
+ return this.execute(expressString, context, errorList, isCache, isTrace, null);
+ }
+/**
+ * 执行一段文本
+ * @param expressString 程序文本
+ * @param context 执行上下文
+ * @param errorList 输出的错误信息List
+ * @param isCache 是否使用Cache中的指令集
+ * @param isTrace 是否输出详细的执行指令信息
+ * @param aLog 输出的log
+ * @return
+ * @throws Exception
+ */
+ public Object execute(String expressString, IExpressContext context,
+ List errorList, boolean isCache, boolean isTrace, Log aLog)
+ throws Exception {
+ InstructionSet parseResult = null;
+ if (isCache == true) {
+ parseResult = expressInstructionSetCache.get(expressString);
+ if (parseResult == null) {
+ synchronized (expressInstructionSetCache) {
+ parseResult = expressInstructionSetCache.get(expressString);
+ if (parseResult == null) {
+ parseResult = this.parseInstructionSet(expressString);
+ expressInstructionSetCache.put(expressString,
+ parseResult);
+ }
+ }
+ }
+ } else {
+ parseResult = this.parseInstructionSet(expressString);
+ }
+ return InstructionSetRunner.executeOuter(this,parseResult,this.loader,context, errorList,
+ isTrace,false,aLog,false);
+ }
+
+ /**
+ * 解析一段文本,生成指令集合
+ * @param text
+ * @return
+ * @throws Exception
+ */
+ public InstructionSet parseInstructionSet(String text)
+ throws Exception {
+ Map selfDefineClass = new HashMap ();
+ for(ExportItem item : this.loader.getExportInfo()){
+ if(item.getType().equals(InstructionSet.TYPE_CLASS)){
+ selfDefineClass.put(item.getName(), item.getName());
+ }
+ }
+
+ ExpressNode root = this.parse.parse(this.rootExpressPackage,text, isTrace,selfDefineClass);
+ InstructionSet result = createInstructionSet(root, "main");
+ if (this.isTrace && log.isDebugEnabled()) {
+ log.debug(result);
+ }
+ return result;
+ }
+ /**
+ * 输出全局定义信息
+ * @return
+ */
+ public ExportItem[] getExportInfo(){
+ return this.loader.getExportInfo();
+ }
+
+ /**
+ * 优先从本地指令集缓存获取指令集,没有的话生成并且缓存在本地
+ * @param expressString
+ * @return
+ * @throws Exception
+ */
+ public InstructionSet getInstructionSetFromLocalCache(String expressString)
+ throws Exception {
+ InstructionSet parseResult = expressInstructionSetCache.get(expressString);
+ if (parseResult == null) {
+ synchronized (expressInstructionSetCache) {
+ parseResult = expressInstructionSetCache.get(expressString);
+ if (parseResult == null) {
+ parseResult = this.parseInstructionSet(expressString);
+ expressInstructionSetCache.put(expressString,
+ parseResult);
+ }
+ }
+ }
+ return parseResult;
+ }
+
+ public InstructionSet createInstructionSet(ExpressNode root, String type)
+ throws Exception {
+ InstructionSet result = new InstructionSet(type);
+ createInstructionSet(root, result);
+ return result;
+ }
+
+ public void createInstructionSet(ExpressNode root, InstructionSet result)
+ throws Exception {
+ Stack forStack = new Stack();
+ createInstructionSetPrivate(result, forStack, root, true);
+ if (forStack.size() > 0) {
+ throw new Exception("For处理错误");
+ }
+ }
+
+ public boolean createInstructionSetPrivate(InstructionSet result,
+ Stack forStack, ExpressNode node,
+ boolean isRoot) throws Exception {
+ InstructionFactory factory = InstructionFactory
+ .getInstructionFactory(node.getInstructionFactory());
+ boolean hasLocalVar = factory.createInstruction(this,result, forStack, node, isRoot);
+ return hasLocalVar;
+ }
+ /**
+ * 获取一个表达式需要的外部变量名称列表
+ * @param express
+ * @return
+ * @throws Exception
+ */
+ public String[] getOutVarNames(String express) throws Exception{
+ return this.parseInstructionSet(express).getOutAttrNames();
+ }
+
+ public String[] getOutFunctionNames(String express) throws Exception{
+ return this.parseInstructionSet(express).getOutFunctionNames();
+ }
+
+
+ public boolean isShortCircuit() {
+ return isShortCircuit;
+ }
+ public void setShortCircuit(boolean isShortCircuit) {
+ this.isShortCircuit = isShortCircuit;
+ }
+}
diff --git a/src/main/java/com/ql/util/express/ExpressUtil.java b/src/main/java/com/ql/util/express/ExpressUtil.java
new file mode 100644
index 0000000000000000000000000000000000000000..a59a3a56a0b31516e4b77d116a59813f2ed339bf
--- /dev/null
+++ b/src/main/java/com/ql/util/express/ExpressUtil.java
@@ -0,0 +1,647 @@
+package com.ql.util.express;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.beanutils.PropertyUtils;
+
+
+/**
+ * 表达式工具类
+ *
+ * @author qhlhl2010@gmail.com
+ *
+ */
+@SuppressWarnings("unchecked")
+public class ExpressUtil {
+ public static final String DT_STRING = "String";
+ public static final String DT_SHORT = "Short";
+ public static final String DT_INTEGER = "Integer";
+ public static final String DT_LONG = "Long";
+ public static final String DT_DOUBLE = "Double";
+ public static final String DT_FLOAT = "Float";
+ public static final String DT_BYTE = "Byte";
+ public static final String DT_CHAR = "Char";
+ public static final String DT_BOOLEAN = "Boolean";
+ public static final String DT_DATE = "Date";
+ public static final String DT_TIME = "Time";
+ public static final String DT_DATETIME = "DateTime";
+ public static final String DT_OBJECT = "Object";
+
+ public static final String DT_short = "short";
+ public static final String DT_int = "int";
+ public static final String DT_long = "long";
+ public static final String DT_double = "double";
+ public static final String DT_float = "float";
+ public static final String DT_byte = "byte";
+ public static final String DT_char = "char";
+ public static final String DT_boolean = "boolean";
+
+ public static Map methodCache = new ConcurrentHashMap();
+
+ public static Class>[][] classMatchs =new Class[][]{
+ //原始数据类型
+ {BigDecimal.class,double.class},{BigDecimal.class,float.class},{BigDecimal.class,long.class},{BigDecimal.class,int.class}, {BigDecimal.class,short.class},{BigDecimal.class,byte.class},
+ {double.class,float.class},{double.class,long.class},{double.class,int.class}, {double.class,short.class},{double.class,byte.class},{double.class,BigDecimal.class},
+ {float.class,long.class}, {float.class,int.class}, {float.class,short.class},{float.class,byte.class},{float.class,BigDecimal.class},
+ {long.class,int.class}, {long.class,short.class}, {long.class,byte.class},
+ {int.class,short.class}, {int.class,byte.class},
+ {short.class,byte.class},
+ //---------
+ {char.class,Character.class},{Character.class,char.class},
+ {boolean.class,Boolean.class},{Boolean.class,boolean.class}
+ };
+
+
+ public static Class> getSimpleDataType(Class> aClass) {
+ if (aClass.isPrimitive()){
+ if (Integer.class.equals(aClass))
+ return Integer.TYPE;
+ if (Short.class.equals(aClass))
+ return Short.TYPE;
+ if (Long.class.equals(aClass))
+ return Long.TYPE;
+ if (Double.class.equals(aClass))
+ return Double.TYPE;
+ if (Float.class.equals(aClass))
+ return Float.TYPE;
+ if (Byte.class.equals(aClass))
+ return Byte.TYPE;
+ if (Character.class.equals(aClass))
+ return Character.TYPE;
+ if (Boolean.class.equals(aClass))
+ return Boolean.TYPE;
+ return aClass;
+ }else{
+ return aClass;
+ }
+ }
+ public static boolean isAssignable(Class> target, Class> source) {
+ if (target == source)
+ return true;
+ if(target.isArray() && source.isArray()){
+ return isAssignable(target.getComponentType(),source.getComponentType());
+ }
+ return isAssignablePrivate(target,source);
+ }
+ public static boolean isAssignablePrivate(Class> target, Class> source) {
+ if (target == source)
+ return true;
+
+ if (target == null)
+ return false;
+ if (source == null)//null转换
+ return !target.isPrimitive();
+
+ if (target.isAssignableFrom(source) == true){
+ return true;
+ }
+ if(source.isPrimitive() && target == Object.class){
+ return true;
+ }
+
+ if (target.isPrimitive() == false) {
+ if (target == Byte.class)
+ target = byte.class;
+ else if (target == Short.class)
+ target = short.class;
+ else if (target == Integer.class)
+ target = int.class;
+ else if (target == Long.class)
+ target = long.class;
+ else if (target == Float.class)
+ target = float.class;
+ else if (target == Double.class)
+ target = double.class;
+ }
+ if (source.isPrimitive() == false) {
+ if (source == Byte.class)
+ source = byte.class;
+ else if (source == Short.class)
+ source = short.class;
+ else if (source == Integer.class)
+ source = int.class;
+ else if (source == Long.class)
+ source = long.class;
+ else if (source == Float.class)
+ source = float.class;
+ else if (source == Double.class)
+ source = double.class;
+ }
+ if (target == source)// 转换后需要在判断一下
+ return true;
+
+ for (int i = 0; i < classMatchs.length; i++) {
+ if (target == classMatchs[i][0] && source == classMatchs[i][1]) {
+ return true;
+ }
+ }
+
+ return false;
+
+ }
+ public static boolean isAssignableOld(Class> lhsType, Class> rhsType) {
+ if (lhsType == null)
+ return false;
+ if (rhsType == null)
+ return !lhsType.isPrimitive();
+
+ if (lhsType.isPrimitive() && rhsType.isPrimitive()) {
+ if (lhsType == rhsType)
+ return true;
+
+ if ((rhsType == Byte.TYPE)
+ && (lhsType == Short.TYPE || lhsType == Integer.TYPE
+ || lhsType == Long.TYPE || lhsType == Float.TYPE || lhsType == Double.TYPE))
+ return true;
+
+ if ((rhsType == Short.TYPE)
+ && (lhsType == Integer.TYPE || lhsType == Long.TYPE
+ || lhsType == Float.TYPE || lhsType == Double.TYPE))
+ return true;
+
+ if ((rhsType == Character.TYPE)
+ && (lhsType == Integer.TYPE || lhsType == Long.TYPE
+ || lhsType == Float.TYPE || lhsType == Double.TYPE))
+ return true;
+
+ if ((rhsType == Integer.TYPE)
+ && (lhsType == Long.TYPE || lhsType == Float.TYPE || lhsType == Double.TYPE))
+ return true;
+
+ if ((rhsType == Long.TYPE)
+ && (lhsType == Float.TYPE || lhsType == Double.TYPE))
+ return true;
+
+ if ((rhsType == Float.TYPE) && (lhsType == Double.TYPE))
+ return true;
+ } else if (lhsType.isAssignableFrom(rhsType))
+ return true;
+
+ return false;
+ }
+
+ public static boolean isSignatureAssignable(Class>[] from, Class>[] to) {
+ for (int i = 0; i < from.length; i++)
+ if (!isAssignable(to[i], from[i]))
+ return false;
+ return true;
+ }
+
+ public static int findMostSpecificSignature(Class>[] idealMatch,
+ Class>[][] candidates) {
+ Class>[] bestMatch = null;
+ int bestMatchIndex = -1;
+
+ for (int i = candidates.length - 1; i >= 0; i--) {// 先从基类开始查找
+ Class>[] targetMatch = candidates[i];
+ if (ExpressUtil.isSignatureAssignable(idealMatch, targetMatch)
+ && ((bestMatch == null) || ExpressUtil
+ .isSignatureAssignable(targetMatch, bestMatch))) {
+ bestMatch = targetMatch;
+ bestMatchIndex = i;
+ }
+ }
+
+ if (bestMatch != null)
+ return bestMatchIndex;
+ else
+ return -1;
+ }
+
+ public static String createCacheKey(Class> aBaseClass,
+ String aMethodName, Class>[] aTypes, boolean aPublicOnly,
+ boolean aIsStatic) {
+ StringBuilder builder = new StringBuilder();
+// builder.append(aPublicOnly).append("-").append(aIsStatic).append("-");
+ builder.append(aBaseClass.getName()).append(".").append(aMethodName)
+ .append(".");
+ if (aTypes == null) {
+ builder.append("null");
+ } else {
+ for (int i = 0; i < aTypes.length; i++) {
+ if (i > 0) {
+ builder.append(",");
+ }
+ if(aTypes[i]== null){
+ builder.append("null");
+ }else{
+ builder.append(aTypes[i].getName());
+ }
+ }
+ }
+// builder.append(")");
+ return builder.toString();
+
+ }
+ public static Method findMethodWithCache(Class> baseClass, String methodName,
+ Class>[] types, boolean publicOnly, boolean isStatic){
+ String key = createCacheKey(baseClass, methodName, types, publicOnly, isStatic);
+ Object result = methodCache.get(key);
+ if(result == null){
+ result = findMethod(baseClass, methodName, types, publicOnly, isStatic);
+ if(result == null){
+ methodCache.put(key, void.class);
+ }else{
+ ((Method)result).setAccessible(true);
+ methodCache.put(key,result);
+ }
+ }else if(result == void.class){
+ result = null;
+ }
+ return (Method)result;
+ }
+
+ public static Method findMethod(Class> baseClass, String methodName,
+ Class>[] types, boolean publicOnly, boolean isStatic) {
+ List candidates = gatherMethodsRecursive(baseClass, methodName,
+ types.length, publicOnly, isStatic, null /* candidates */);
+ Method method = findMostSpecificMethod(types, (Method[]) candidates
+ .toArray(new Method[0]));
+ return method;
+ }
+
+ public static Constructor> findConstructorWithCache(Class> baseClass, Class>[] types) {
+ String key = createCacheKey(baseClass, "new", types, true, false);
+ Constructor> result = (Constructor>)methodCache.get(key);
+ if(result == null){
+ result = findConstructor(baseClass,types);
+ methodCache.put(key, result);
+ }
+ return result;
+ }
+
+ private static Constructor> findConstructor(Class> baseClass, Class>[] types) {
+ Constructor>[] constructors = baseClass.getConstructors();
+ List> constructorList = new ArrayList>();
+ List[]> listClass = new ArrayList[]>();
+ for (int i = 0; i < constructors.length; i++) {
+ if (constructors[i].getParameterTypes().length == types.length) {
+ listClass.add(constructors[i].getParameterTypes());
+ constructorList.add(constructors[i]);
+ }
+ }
+
+ int match = findMostSpecificSignature(types, (Class[][]) listClass
+ .toArray(new Class[0][]));
+ return match == -1 ? null : constructorList.get(match);
+ }
+
+ public static Method findMostSpecificMethod(Class>[] idealMatch,
+ Method[] methods) {
+ Class>[][] candidateSigs = new Class[methods.length][];
+ for (int i = 0; i < methods.length; i++)
+ candidateSigs[i] = methods[i].getParameterTypes();
+
+ int match = findMostSpecificSignature(idealMatch, candidateSigs);
+ return match == -1 ? null : methods[match];
+
+ }
+
+ private static List gatherMethodsRecursive(Class> baseClass,
+ String methodName, int numArgs, boolean publicOnly,
+ boolean isStatic, List candidates) {
+ if (candidates == null)
+ candidates = new ArrayList();
+
+ addCandidates(baseClass.getDeclaredMethods(), methodName, numArgs,
+ publicOnly, isStatic, candidates);
+
+ Class>[] intfs = baseClass.getInterfaces();
+ for (int i = 0; i < intfs.length; i++)
+ gatherMethodsRecursive(intfs[i], methodName, numArgs, publicOnly,
+ isStatic, candidates);
+
+ Class> superclass = baseClass.getSuperclass();
+ if (superclass != null)
+ gatherMethodsRecursive(superclass, methodName, numArgs, publicOnly,
+ isStatic, candidates);
+
+ return candidates;
+ }
+
+ private static List addCandidates(Method[] methods, String methodName,
+ int numArgs, boolean publicOnly, boolean isStatic, List candidates) {
+ for (int i = 0; i < methods.length; i++) {
+ Method m = methods[i];
+ if (m.getName().equals(methodName)
+ && (m.getParameterTypes().length == numArgs)
+ && (publicOnly == false || isPublic(m)
+ && (isStatic == false || isStatic(m))))
+ candidates.add(m);
+ }
+ return candidates;
+ }
+
+ public static boolean isPublic(Class> c) {
+ return Modifier.isPublic(c.getModifiers());
+ }
+
+ public static boolean isPublic(Method m) {
+ return Modifier.isPublic(m.getModifiers());
+ }
+
+ public static boolean isStatic(Method m) {
+ return Modifier.isStatic(m.getModifiers());
+ }
+
+ public static Class> getJavaClass(String type) {
+ int index = type.indexOf("[]");
+ if (index < 0)
+ return getJavaClassInner(type);
+
+ StringBuilder arrayString = new StringBuilder();
+ arrayString.append("[");
+ String baseType = type.substring(0, index);
+ while ((index = type.indexOf("[]", index + 2)) >= 0) {
+ arrayString.append("[");
+ }
+ Class> baseClass = getJavaClassInner(baseType);
+
+ try {
+ String baseName = "";
+ if (baseClass.isPrimitive() == false) {
+ return loadClass(arrayString.toString() + "L"
+ + baseClass.getName() + ";");
+ } else {
+ if (baseClass.equals(boolean.class)) {
+ baseName = "Z";
+ } else if (baseClass.equals(byte.class)) {
+ baseName = "B";
+ } else if (baseClass.equals(char.class)) {
+ baseName = "C";
+ } else if (baseClass.equals(double.class)) {
+ baseName = "D";
+ } else if (baseClass.equals(float.class)) {
+ baseName = "F";
+ } else if (baseClass.equals(int.class)) {
+ baseName = "I";
+ } else if (baseClass.equals(long.class)) {
+ baseName = "J";
+ } else if (baseClass.equals(short.class)) {
+ baseName = "S";
+ }
+ return loadClass(arrayString.toString() + baseName);
+ }
+ } catch (ClassNotFoundException ex) {
+ throw new RuntimeException(ex);
+ }
+
+ }
+
+ public static Class> getJavaClassInner(String type) {
+
+ if (type.equals(DT_STRING))
+ return String.class;
+ if (type.equals(DT_SHORT))
+ return Short.class;
+ if (type.equals(DT_INTEGER))
+ return Integer.class;
+ if (type.equals(DT_LONG))
+ return Long.class;
+ if (type.equals(DT_DOUBLE))
+ return Double.class;
+ if (type.equals(DT_FLOAT))
+ return Float.class;
+ if (type.equals(DT_BYTE))
+ return Byte.class;
+ if (type.equals(DT_CHAR) || type.equals("Character"))
+ return Character.class;
+ if (type.equals(DT_BOOLEAN))
+ return Boolean.class;
+ if (type.equals(DT_DATE))
+ return java.sql.Date.class;
+ if (type.equals(DT_TIME))
+ return java.sql.Time.class;
+ if (type.equals(DT_DATETIME))
+ return java.sql.Timestamp.class;
+ if (type.equals(DT_OBJECT))
+ return Object.class;
+ if (type.equals(DT_short))
+ return short.class;
+ if (type.equals(DT_int))
+ return int.class;
+ if (type.equals(DT_long))
+ return long.class;
+ if (type.equals(DT_double))
+ return double.class;
+ if (type.equals(DT_float))
+ return float.class;
+ if (type.equals(DT_byte))
+ return byte.class;
+ if (type.equals(DT_char))
+ return char.class;
+ if (type.equals(DT_boolean))
+ return boolean.class;
+ try {
+ return loadClass(type);
+ } catch (ClassNotFoundException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ public static String getClassName(Class> className) {
+ if(className == null){
+ return null;
+ }
+ String name = className.getName();
+ return getClassName(name);
+ }
+
+ private static String getClassName(String name) {
+ String arrays = "";
+ if (name.indexOf("[") >= 0) {
+ int point = 0;
+ while (name.charAt(point) == '[') {
+ arrays = arrays + "[]";
+ ++point;
+ }
+ if (name.charAt(point) == 'L') {
+ name = name.substring(point + 1, name.length() - 1);
+ } else if (name.charAt(point) == 'Z') {
+ name = "boolean";
+ } else if (name.charAt(point) == 'B') {
+ name = "byte";
+ } else if (name.charAt(point) == 'C') {
+ name = "char";
+ } else if (name.charAt(point) == 'D') {
+ name = "double";
+ } else if (name.charAt(point) == 'F') {
+ name = "float";
+ } else if (name.charAt(point) == 'I') {
+ name = "int";
+ } else if (name.charAt(point) == 'J') {
+ name = "long";
+ } else if (name.charAt(point) == 'S') {
+ name = "short";
+ }
+ }
+ int index = name.lastIndexOf('.');
+ if (index > 0 && name.substring(0, index).equals("java.lang") == true) {
+ name = name.substring(index + 1);
+ }
+ name = name + arrays;
+ return name;
+ }
+ public static Class> loadClass(String name) throws ClassNotFoundException {
+ return Class.forName(name);
+ }
+
+ /**
+ * 替换字符串中的参数 replaceString("$1强化$2实施$2",new String[]{"qq","ff"})
+ * ="qq 强化 ff 实施 ff"
+ *
+ * @param str
+ * @param parameters
+ * @return
+ * @throws Exception
+ */
+ public static String replaceString(String str, Object[] parameters)
+ throws Exception {
+ if (str == null || parameters == null || parameters.length == 0) {
+ return str;
+ }
+ Pattern p = Pattern.compile("\\$\\d+");
+ Matcher m = p.matcher(str);
+ StringBuffer sb = new StringBuffer();
+ while (m.find()) {
+ int index = Integer.parseInt(m.group().substring(1)) - 1;
+ if (index < 0 || index >= parameters.length) {
+ throw new Exception("设置的参数位置$" + (index + 1) + "超过了范围 "
+ + parameters.length);
+ }
+ m.appendReplacement(sb, " " + parameters[index].toString() + " ");
+ }
+ m.appendTail(sb);
+ return sb.toString();
+ }
+
+ public static Object getProperty(Object bean, Object name) {
+ try {
+ if(bean.getClass().isArray() && name.equals("length")){
+ return Array.getLength(bean);
+ }else if (bean instanceof Class) {
+ if(name.equals("class")){
+ return bean;
+ }else{
+ Field f = ((Class>) bean).getDeclaredField(name.toString());
+ return f.get(null);
+ }
+ }else if(bean instanceof Map ){
+ return ((Map,?>)bean).get(name);
+ }else {
+ Object obj = PropertyUtils.getProperty(bean, name.toString());
+ return obj;
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ public static Class> getPropertyClass(Object bean, Object name) {
+ try {
+ if(bean.getClass().isArray() && name.equals("length")){
+ return int.class;
+ }else if (bean instanceof Class) {
+ if(name.equals("class")){
+ return Class.class;
+ }else{
+ Field f = ((Class>) bean).getDeclaredField(name.toString());
+ return f.getType();
+ }
+ }else if(bean instanceof Map ){
+ Object o = ((Map,?>)bean).get(name);
+ if(o == null){
+ return null;
+ }else{
+ return o.getClass();
+ }
+ }else {
+ return PropertyUtils.getPropertyDescriptor(bean, name.toString()).getPropertyType();
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ public static void setProperty(Object bean, Object name, Object value) {
+ try {
+ if (bean instanceof Class) {
+ Field f = ((Class>) bean).getDeclaredField(name.toString());
+ f.set(null, value);
+ }else if(bean instanceof Map ){
+ ((Map
+ * Description:表达式计算的运算符号
+ * Copyright: Copyright (c) 2001
+ * Company:
+ * @author 墙辉
+ * @version 1.0
+ */
+
+package com.ql.util.express.instruction.op;
+
+import java.util.List;
+
+import com.ql.util.express.ArraySwap;
+import com.ql.util.express.ExpressUtil;
+import com.ql.util.express.InstructionSetContext;
+import com.ql.util.express.OperateData;
+import com.ql.util.express.instruction.opdata.OperateDataAttr;
+
+/**
+ * 操作符号定义
+ *
+ * @author qhlhl2010@gmail.com
+ *
+ */
+
+public abstract class OperatorBase implements java.io.Serializable {
+
+ protected String aliasName;
+
+ protected String name;
+
+ protected String errorInfo;
+ /**
+ * 是否需要高精度计算
+ */
+ protected boolean isPrecise = false;
+ /**
+ * 操作数描述
+ */
+ protected String[] operDataDesc;
+ /**
+ * 操作数的其它定义
+ */
+ protected String[] operDataAnnotation;
+ public Object[] toObjectList(InstructionSetContext parent, ArraySwap list)
+ throws Exception {
+ if (list == null) {
+ return new Object[0];
+ }
+ Object[] result = new Object[list.length];
+ OperateData p;
+ for (int i = 0; i < list.length; i++) {
+ p = list.get(i);
+ if(p instanceof OperateDataAttr){
+ result[i] = ((OperateDataAttr) p).getName()+":"+p.getObject(parent);
+ }else{
+ result[i] = p.getObject(parent);
+ }
+ }
+ return result;
+ }
+ public OperateData execute(InstructionSetContext context,
+ ArraySwap list, List errorList) throws Exception {
+ OperateData result = null;
+ result = this.executeInner(context, list);
+ //输出错误信息
+ if (errorList != null && this.errorInfo != null && result != null) {
+ Object obj = result.getObject(context);
+ if ( obj != null
+ && obj instanceof Boolean
+ && ((Boolean) obj).booleanValue() == false) {
+ String tmpStr = ExpressUtil.replaceString(this.errorInfo,
+ toObjectList(context, list));
+ if(errorList.contains(tmpStr) == false){
+ errorList.add(tmpStr);
+ }
+ }
+ }
+ return result;
+ }
+ public String toString(){
+ if(this.aliasName != null){
+ return this.aliasName;
+ }else{
+ return this.name;
+ }
+ }
+ public abstract OperateData executeInner(InstructionSetContext parent, ArraySwap list) throws Exception;
+
+ public String[] getOperDataDesc(){
+ return this.operDataDesc;
+ }
+ public String[] getOperDataAnnotaion(){
+ return this.operDataAnnotation;
+ }
+ public void setName(String aName) {
+ this.name = aName;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public String getAliasName() {
+ if(this.aliasName != null){
+ return this.aliasName;
+ }else{
+ return this.name;
+ }
+ }
+
+ public void setAliasName(String aliasName) {
+ this.aliasName = aliasName;
+ }
+
+ public boolean isPrecise() {
+ return isPrecise;
+ }
+ public void setPrecise(boolean isPrecise) {
+ this.isPrecise = isPrecise;
+ }
+ public String getErrorInfo() {
+ return errorInfo;
+ }
+
+ public void setErrorInfo(String errorInfo) {
+ this.errorInfo = errorInfo;
+ }
+}
+
+class OperatorFunction extends OperatorBase {
+ public OperatorFunction(String aName) {
+ this.name = aName;
+ }
+ public OperatorFunction(String aAliasName, String aName, String aErrorInfo) {
+ this.name = aName;
+ this.aliasName = aAliasName;
+ this.errorInfo = aErrorInfo;
+ }
+
+ public OperateData executeInner(InstructionSetContext context, ArraySwap list) throws Exception {
+ throw new Exception("还没有实现");
+ }
+}
+
+class OperatorReturn extends OperatorBase{
+ public OperatorReturn(String name) {
+ this.name = name;
+ }
+ public OperatorReturn(String aAliasName, String aName, String aErrorInfo) {
+ this.name = aName;
+ this.aliasName = aAliasName;
+ this.errorInfo = aErrorInfo;
+ }
+ public OperateData executeInner(InstructionSetContext parent, ArraySwap list) throws Exception {
+ return executeInner(parent);
+ }
+
+ public OperateData executeInner(InstructionSetContext parent) throws Exception {
+ throw new Exception("return 是通过特殊指令来实现的,不能支持此方法");
+ }
+}
+class OperatorCall extends OperatorBase{
+ public OperatorCall(String name) {
+ this.name = name;
+ }
+ public OperatorCall(String aAliasName, String aName, String aErrorInfo) {
+ this.name = aName;
+ this.aliasName = aAliasName;
+ this.errorInfo = aErrorInfo;
+ }
+ public OperateData executeInner(InstructionSetContext parent, ArraySwap list) throws Exception {
+ throw new Exception("call 是通过特殊指令来实现的,不能支持此方法");
+ }
+}
+
+class OperatorBreak extends OperatorBase{
+ public OperatorBreak(String name) {
+ this.name = name;
+ }
+ public OperatorBreak(String aAliasName, String aName, String aErrorInfo) {
+ this.name = aName;
+ this.aliasName = aAliasName;
+ this.errorInfo = aErrorInfo;
+ }
+ public OperateData executeInner(InstructionSetContext parent, ArraySwap list) throws Exception {
+ throw new Exception("OperatorBreak 是通过特殊指令来实现的,不能支持此方法");
+ }
+}
+class OperatorContinue extends OperatorBase{
+ public OperatorContinue(String name) {
+ this.name = name;
+ }
+ public OperatorContinue(String aAliasName, String aName, String aErrorInfo) {
+ this.name = aName;
+ this.aliasName = aAliasName;
+ this.errorInfo = aErrorInfo;
+ }
+ public OperateData executeInner(InstructionSetContext parent, ArraySwap list) throws Exception {
+ throw new Exception("OperatorContinue 是通过特殊指令来实现的,不能支持此方法");
+ }
+}
+
+class OperatorFor extends OperatorBase {
+ public OperatorFor(String aName) {
+ this.name = aName;
+ }
+
+ public OperatorFor(String aAliasName, String aName, String aErrorInfo) {
+ this.name = aName;
+ this.aliasName = aAliasName;
+ this.errorInfo = aErrorInfo;
+ }
+
+ public OperateData executeInner(InstructionSetContext parent, ArraySwap list) throws Exception {
+ throw new Exception("cache 是通过特殊指令来实现的,不能支持此方法");
+ }
+
+}
diff --git a/src/main/java/com/ql/util/express/instruction/op/OperatorCast.java b/src/main/java/com/ql/util/express/instruction/op/OperatorCast.java
new file mode 100644
index 0000000000000000000000000000000000000000..dcc0d322a67f721230666a152bee5b9ea417acd2
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/op/OperatorCast.java
@@ -0,0 +1,20 @@
+package com.ql.util.express.instruction.op;
+
+import com.ql.util.express.ArraySwap;
+import com.ql.util.express.ExpressUtil;
+import com.ql.util.express.InstructionSetContext;
+import com.ql.util.express.OperateData;
+import com.ql.util.express.instruction.OperateDataCacheManager;
+
+public class OperatorCast extends OperatorBase {
+ public OperatorCast(String aName) {
+ this.name = aName;
+ }
+
+ public OperateData executeInner(InstructionSetContext parent, ArraySwap list) throws Exception {
+ Class> tmpClass = (Class>) list.get(0).getObject(parent);
+ Object castObj = ExpressUtil.castObject(list.get(1).getObject(parent), tmpClass,true);
+ OperateData result = OperateDataCacheManager.fetchOperateData(castObj,tmpClass);
+ return result;
+ }
+}
diff --git a/src/main/java/com/ql/util/express/instruction/op/OperatorDef.java b/src/main/java/com/ql/util/express/instruction/op/OperatorDef.java
new file mode 100644
index 0000000000000000000000000000000000000000..2980dc1af16147b8443e66889c01ada0ea2c93ae
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/op/OperatorDef.java
@@ -0,0 +1,33 @@
+package com.ql.util.express.instruction.op;
+
+import com.ql.util.express.ArraySwap;
+import com.ql.util.express.InstructionSetContext;
+import com.ql.util.express.OperateData;
+import com.ql.util.express.instruction.OperateDataCacheManager;
+import com.ql.util.express.instruction.opdata.OperateDataLocalVar;
+import com.ql.util.express.instruction.opdata.OperateDataVirClass;
+
+public class OperatorDef extends OperatorBase {
+ public OperatorDef(String aName) {
+ this.name = aName;
+ }
+ public OperatorDef(String aAliasName, String aName, String aErrorInfo) {
+ this.name = aName;
+ this.aliasName = aAliasName;
+ this.errorInfo = aErrorInfo;
+ }
+
+ public OperateData executeInner(InstructionSetContext context, ArraySwap list) throws Exception {
+ Object type = list.get(0).getObject(context);
+ String varName = (String)list.get(1).getObject(context);
+ Class> tmpClass = null;
+ if(type instanceof Class ){
+ tmpClass = (Class>) type;
+ }else{
+ tmpClass = OperateDataVirClass.class;
+ }
+ OperateDataLocalVar result = OperateDataCacheManager.fetchOperateDataLocalVar(varName,tmpClass);
+ context.addSymbol(varName, result);
+ return result;
+ }
+}
diff --git a/src/main/java/com/ql/util/express/instruction/op/OperatorDoubleAddReduce.java b/src/main/java/com/ql/util/express/instruction/op/OperatorDoubleAddReduce.java
new file mode 100644
index 0000000000000000000000000000000000000000..d5103a3592145d72bcd9cdbe7de1b8dda35bf881
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/op/OperatorDoubleAddReduce.java
@@ -0,0 +1,32 @@
+package com.ql.util.express.instruction.op;
+
+import com.ql.util.express.ArraySwap;
+import com.ql.util.express.ExpressUtil;
+import com.ql.util.express.InstructionSetContext;
+import com.ql.util.express.OperateData;
+import com.ql.util.express.OperatorOfNumber;
+import com.ql.util.express.instruction.OperateDataCacheManager;
+
+public class OperatorDoubleAddReduce extends OperatorBase {
+ public OperatorDoubleAddReduce(String name) {
+ this.name = name;
+ }
+
+ public OperateData executeInner(InstructionSetContext parent,
+ ArraySwap list) throws Exception {
+ Object obj = list.get(0).getObject(parent);
+ Object result = null;
+ if (this.getName().equals("++")) {
+ result = OperatorOfNumber.add(obj, 1,this.isPrecise);
+ } else if (this.getName().equals("--")) {
+ result = OperatorOfNumber.subtract(obj, 1,this.isPrecise);
+ }
+ ((OperateData)list.get(0)).setObject(parent, result);
+
+ if(result == null){
+ return OperateDataCacheManager.fetchOperateData(null,null);
+ }else{
+ return OperateDataCacheManager.fetchOperateData(result,ExpressUtil.getSimpleDataType(result.getClass()));
+ }
+ }
+}
diff --git a/src/main/java/com/ql/util/express/instruction/op/OperatorEqualsLessMore.java b/src/main/java/com/ql/util/express/instruction/op/OperatorEqualsLessMore.java
new file mode 100644
index 0000000000000000000000000000000000000000..ce970d5906f3e39384383b051e2f4c845f1f946b
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/op/OperatorEqualsLessMore.java
@@ -0,0 +1,73 @@
+package com.ql.util.express.instruction.op;
+
+import com.ql.util.express.Operator;
+
+ /**
+ * 处理 =,==,>,>=,<,<=,!=,<>
+ */
+public class OperatorEqualsLessMore extends Operator {
+ public OperatorEqualsLessMore(String aName) {
+ this.name = aName;
+ }
+
+ public OperatorEqualsLessMore(String aAliasName, String aName,
+ String aErrorInfo) {
+ this.name = aName;
+ this.aliasName = aAliasName;
+ this.errorInfo = aErrorInfo;
+ }
+
+ public Object executeInner(Object[] list) throws Exception {
+ return executeInner(list[0], list[1]);
+ }
+
+ public Object executeInner(Object op1,Object op2) throws Exception {
+ boolean result = executeInner(this.name, op1, op2);
+ return result;
+ }
+
+ public static boolean executeInner(String opStr, Object obj1, Object obj2)
+ throws Exception {
+
+ if (obj1 == null && obj2 == null) {
+ if (opStr.equals("==")) {
+ return true;
+ } else if (opStr.equals("!=") || opStr.equals("<>")) {
+ return false;
+ } else {
+ throw new Exception("两个空操作数不能执行这个操作:" + opStr);
+ }
+ } else if (obj1 == null || obj2 == null) {
+ if (opStr.equals("==")) {
+ return false;
+ } else if (opStr.equals("!=") || opStr.equals("<>")) {
+ return true;
+ } else {
+ throw new Exception("空操作数不能执行这个操作:" + opStr);
+ }
+ }
+
+ int i = Operator.compareData(obj1, obj2);
+ boolean result = false;
+ if (i > 0) {
+ if (opStr.equals(">") || opStr.equals(">=") || opStr.equals("!=")
+ || opStr.equals("<>"))
+ result = true;
+ else
+ result = false;
+ } else if (i == 0) {
+ if (opStr.equals("=") || opStr.equals("==") || opStr.equals(">=")
+ || opStr.equals("<="))
+ result = true;
+ else
+ result = false;
+ } else if (i < 0) {
+ if (opStr.equals("<") || opStr.equals("<=") || opStr.equals("!=")
+ || opStr.equals("<>"))
+ result = true;
+ else
+ result = false;
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/com/ql/util/express/instruction/op/OperatorEvaluate.java b/src/main/java/com/ql/util/express/instruction/op/OperatorEvaluate.java
new file mode 100644
index 0000000000000000000000000000000000000000..e56ba5cfb84a4ab66179feaa5989d6ab26538bb2
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/op/OperatorEvaluate.java
@@ -0,0 +1,41 @@
+package com.ql.util.express.instruction.op;
+
+import com.ql.util.express.ArraySwap;
+import com.ql.util.express.ExpressUtil;
+import com.ql.util.express.InstructionSetContext;
+import com.ql.util.express.OperateData;
+
+public class OperatorEvaluate extends OperatorBase {
+ public OperatorEvaluate(String name) {
+ this.name = name;
+ }
+ public OperatorEvaluate(String aAliasName, String aName, String aErrorInfo) {
+ this.name = aName;
+ this.aliasName = aAliasName;
+ this.errorInfo = aErrorInfo;
+ }
+ public OperateData executeInner(InstructionSetContext parent, ArraySwap list) throws Exception {
+ return executeInner(parent, list.get(0), list.get(1));
+ }
+
+ public OperateData executeInner(InstructionSetContext parent,
+ OperateData op1, OperateData op2) throws Exception {
+ Class> targetType = op1.getDefineType();
+ Class> sourceType = op2.getType(parent);
+ if (targetType != null) {
+ if (ExpressUtil.isAssignable(targetType, sourceType) == false) {
+ throw new Exception("赋值时候,类型转换错误:"
+ + ExpressUtil.getClassName(sourceType) + " 不能转换为 "
+ + ExpressUtil.getClassName(targetType));
+ }
+
+ }
+ Object result = op2.getObject(parent);
+ if(targetType != null){
+ result = ExpressUtil.castObject(result,targetType,false);
+ }
+ op1.setObject(parent,result);
+ return op1;
+ }
+
+}
diff --git a/src/main/java/com/ql/util/express/instruction/op/OperatorExportAlias.java b/src/main/java/com/ql/util/express/instruction/op/OperatorExportAlias.java
new file mode 100644
index 0000000000000000000000000000000000000000..f3ed0b53e481e7df16ed26b99db307ecd27fbcbf
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/op/OperatorExportAlias.java
@@ -0,0 +1,26 @@
+package com.ql.util.express.instruction.op;
+
+import com.ql.util.express.ArraySwap;
+import com.ql.util.express.InstructionSetContext;
+import com.ql.util.express.OperateData;
+import com.ql.util.express.instruction.opdata.OperateDataAlias;
+import com.ql.util.express.instruction.opdata.OperateDataAttr;
+
+public class OperatorExportAlias extends OperatorBase {
+ public OperatorExportAlias(String aName) {
+ this.name = aName;
+ }
+ public OperatorExportAlias(String aAliasName, String aName, String aErrorInfo) {
+ this.name = aName;
+ this.aliasName = aAliasName;
+ this.errorInfo = aErrorInfo;
+ }
+
+ public OperateData executeInner(InstructionSetContext context, ArraySwap list) throws Exception {
+ String varName = (String)list.get(0).getObjectInner(context);
+ OperateDataAttr realAttr = (OperateDataAttr)list.get(1);
+ OperateDataAttr result = new OperateDataAlias(varName,realAttr);
+ context.exportSymbol(varName, result);
+ return result;
+ }
+}
diff --git a/src/main/java/com/ql/util/express/instruction/op/OperatorExportDef.java b/src/main/java/com/ql/util/express/instruction/op/OperatorExportDef.java
new file mode 100644
index 0000000000000000000000000000000000000000..158519056d7a39e966f770669440721a9945c553
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/op/OperatorExportDef.java
@@ -0,0 +1,27 @@
+package com.ql.util.express.instruction.op;
+
+import com.ql.util.express.ArraySwap;
+import com.ql.util.express.InstructionSetContext;
+import com.ql.util.express.OperateData;
+import com.ql.util.express.instruction.opdata.OperateDataAttr;
+
+public class OperatorExportDef extends OperatorBase {
+ public OperatorExportDef(String aName) {
+ this.name = aName;
+ }
+ public OperatorExportDef(String aAliasName, String aName, String aErrorInfo) {
+ this.name = aName;
+ this.aliasName = aAliasName;
+ this.errorInfo = aErrorInfo;
+ }
+
+ public OperateData executeInner(InstructionSetContext context, ArraySwap list) throws Exception {
+ Class> tmpClass = (Class>) list.get(0).getObject(context);
+ String varName = (String)list.get(1).getObject(context);
+ //OperateDataLocalVar result = new OperateDataLocalVar(varName,tmpClass);
+ //context.exportSymbol(varName, result);
+ OperateDataAttr result = (OperateDataAttr)context.getSymbol(varName);
+ result.setDefineType(tmpClass);
+ return result;
+ }
+}
diff --git a/src/main/java/com/ql/util/express/instruction/op/OperatorFactory.java b/src/main/java/com/ql/util/express/instruction/op/OperatorFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..dfb34ddd7e67b9371babb832a345dc3aed7e701a
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/op/OperatorFactory.java
@@ -0,0 +1,135 @@
+package com.ql.util.express.instruction.op;
+
+import java.lang.reflect.Constructor;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.ql.util.express.parse.ExpressNode;
+
+public class OperatorFactory {
+
+ /**
+ * 是否需要高精度计算
+ */
+ protected boolean isPrecise = false;
+ private Map operator = new HashMap();
+
+ public OperatorFactory(boolean aIsPrecise){
+ this.isPrecise = aIsPrecise;
+ addOperator("new",new OperatorNew("new"));
+ addOperator("anonymousNewArray",new OperatorAnonymousNewArray("anonymousNewArray"));
+ addOperator("NewList",new OperatorAnonymousNewList("NewList"));
+ addOperator(":",new OperatorKeyValue(":"));
+ addOperator("NewMap",new OperatorAnonymousNewMap("NewMap"));
+ addOperator("def", new OperatorDef("def"));
+ addOperator("exportDef", new OperatorExportDef("exportDef"));
+ addOperator("!",new OperatorNot("!"));
+ addOperator("*", new OperatorMultiDiv("*"));
+ addOperator("/", new OperatorMultiDiv("/"));
+ addOperator("%", new OperatorMultiDiv("%"));
+ addOperator("mod", new OperatorMultiDiv("mod"));
+ addOperator("+",new OperatorAdd("+"));
+ addOperator("-",new OperatorReduce("-"));
+ addOperator("<",new OperatorEqualsLessMore("<"));
+ addOperator(">",new OperatorEqualsLessMore(">"));
+ addOperator("<=",new OperatorEqualsLessMore("<="));
+ addOperator(">=",new OperatorEqualsLessMore(">="));
+ addOperator("==",new OperatorEqualsLessMore("=="));
+ addOperator("!=",new OperatorEqualsLessMore("!="));
+ addOperator("<>",new OperatorEqualsLessMore("<>"));
+ addOperator("&&",new OperatorAnd("&&"));
+ addOperator("||",new OperatorOr("||"));
+ addOperator("nor",new OperatorNor("nor"));
+ addOperator("=",new OperatorEvaluate("="));
+ addOperator("exportAlias",new OperatorExportAlias("exportAlias"));
+ addOperator("alias",new OperatorAlias("alias"));
+ addOperator("break",new OperatorBreak("break"));
+ addOperator("continue",new OperatorContinue("continue"));
+ addOperator("return",new OperatorReturn("return"));
+ addOperator("ARRAY_CALL",new OperatorArray("ARRAY_CALL"));
+ addOperator("++",new OperatorDoubleAddReduce("++"));
+ addOperator("--",new OperatorDoubleAddReduce("--"));
+ addOperator("cast", new OperatorCast("cast"));
+ addOperator("macro",new OperatorMacro("macro"));
+ addOperator("function",new OperatorFunction("function"));
+ addOperator("in", new OperatorIn("in"));
+ addOperator("like", new OperatorLike("like"));
+ }
+ public void addOperator(String name, OperatorBase op) {
+ OperatorBase oldOp = this.operator.get(name);
+ if (oldOp != null) {
+ throw new RuntimeException("重复定义操作符:" + name + "定义1:"
+ + oldOp.getClass() + " 定义2:" + op.getClass());
+ }
+ op.setPrecise(this.isPrecise);
+ op.setAliasName(name);
+ operator.put(name, op);
+ }
+ public OperatorBase replaceOperator(String name, OperatorBase op){
+ OperatorBase old = this.operator.remove(name);
+ this.addOperator(name, op);
+ return old;
+ }
+
+ @SuppressWarnings("unchecked")
+ public void addOperatorWithAlias(String aAliasName,String name,String errorInfo) throws Exception{
+ if (this.operator.containsKey(name) == false){
+ throw new Exception(name + " 不是系统级别的操作符号,不能设置别名");
+ }else{
+ OperatorBase orgiOperator = this.operator.get(name);
+ if(orgiOperator == null){
+ throw new Exception(name + " 不能被设置别名");
+ }
+ OperatorBase destOperator = null;
+ if (orgiOperator instanceof CanClone) {
+ destOperator = ((CanClone)orgiOperator).cloneMe(aAliasName, errorInfo);
+ } else {
+ Class opClass = (Class) orgiOperator.getClass();
+ Constructor constructor = null;
+ try {
+ constructor = (Constructor) opClass
+ .getConstructor(String.class, String.class,String.class);
+ } catch (Exception e) {
+ throw new Exception(name + " 不能被设置别名:" + e.getMessage());
+ }
+ if (constructor == null) {
+ throw new Exception(name + " 不能被设置别名");
+ }
+ destOperator = constructor.newInstance(aAliasName, name,errorInfo);
+ }
+ if(this.operator.containsKey(aAliasName)){
+ throw new RuntimeException("操作符号:\"" + aAliasName + "\" 已经存在");
+ }
+ this.addOperator(aAliasName,destOperator);
+ }
+ }
+ public boolean isExistOperator(String operName) throws Exception {
+ return operator.containsKey(operName);
+ }
+ public OperatorBase getOperator(String aOperName){
+ return this.operator.get(aOperName);
+ }
+
+ /**
+ * 创建一个新的操作符实例
+ */
+ public OperatorBase newInstance(ExpressNode opItem) throws Exception {
+ OperatorBase op = operator.get(opItem.getNodeType().getName());
+ if (op == null) {
+ op = operator.get(opItem.getTreeType().getName());
+ }
+ if(op == null){
+ op = operator.get(opItem.getValue());
+ }
+ if (op == null)
+ throw new Exception("没有为\"" + opItem.getValue() + "\"定义操作符处理对象");
+ return op;
+ }
+ public OperatorBase newInstance(String opName) throws Exception {
+ OperatorBase op = operator.get(opName);
+ if (op == null){
+ throw new Exception("没有为\"" + opName + "\"定义操作符处理对象");
+ }
+ return op;
+ }
+}
diff --git a/src/main/java/com/ql/util/express/instruction/op/OperatorField.java b/src/main/java/com/ql/util/express/instruction/op/OperatorField.java
new file mode 100644
index 0000000000000000000000000000000000000000..77917e564ec594b9247c4848e693640436c29956
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/op/OperatorField.java
@@ -0,0 +1,26 @@
+package com.ql.util.express.instruction.op;
+
+import com.ql.util.express.ArraySwap;
+import com.ql.util.express.InstructionSetContext;
+import com.ql.util.express.OperateData;
+import com.ql.util.express.instruction.OperateDataCacheManager;
+import com.ql.util.express.instruction.opdata.OperateDataField;
+
+public class OperatorField extends OperatorBase {
+ String filedName;
+ public OperatorField() {
+ this.name = "FieldCall";
+ }
+ public OperatorField(String aFieldName) {
+ this.name = "FieldCall";
+ this.filedName = aFieldName;
+
+ }
+ public OperateData executeInner(InstructionSetContext parent, ArraySwap list) throws Exception {
+ Object obj = list.get(0).getObject(parent);
+ return OperateDataCacheManager.fetchOperateDataField(obj,this.filedName);
+ }
+ public String toString(){
+ return this.name + ":" + this.filedName;
+ }
+}
diff --git a/src/main/java/com/ql/util/express/instruction/op/OperatorIf.java b/src/main/java/com/ql/util/express/instruction/op/OperatorIf.java
new file mode 100644
index 0000000000000000000000000000000000000000..a7070f97f03b730a2335c980ee9b0385f0e2aff2
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/op/OperatorIf.java
@@ -0,0 +1,40 @@
+package com.ql.util.express.instruction.op;
+
+import com.ql.util.express.ArraySwap;
+import com.ql.util.express.InstructionSetContext;
+import com.ql.util.express.OperateData;
+
+public class OperatorIf extends OperatorBase {
+ public OperatorIf(String aName) {
+ this.name = aName;
+ }
+
+ public OperatorIf(String aAliasName, String aName, String aErrorInfo) {
+ this.name = aName;
+ this.aliasName = aAliasName;
+ this.errorInfo = aErrorInfo;
+ }
+
+ public OperateData executeInner(InstructionSetContext parent, ArraySwap list) throws Exception {
+ if(list.length <2){
+ throw new Exception("\"" + this.aliasName + "\"操作至少要两个操作数");
+ }
+ Object obj = list.get(0).getObject(parent);
+ if (obj == null) {
+ String msg ="\"" + this.aliasName + "\"的判断条件不能为空";
+ throw new Exception(msg);
+ } else if ((obj instanceof Boolean) == false) {
+ String msg = "\"" + this.aliasName + "\"的判断条件 必须是 Boolean,不能是:";
+ throw new Exception(msg + obj.getClass().getName());
+ } else {
+ if (((Boolean)obj).booleanValue() == true){
+ return list.get(1);
+ }else{
+ if(list.length == 3){
+ return list.get(2);
+ }
+ }
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/com/ql/util/express/instruction/op/OperatorIn.java b/src/main/java/com/ql/util/express/instruction/op/OperatorIn.java
new file mode 100644
index 0000000000000000000000000000000000000000..a063f2c1279f4f36e7ec8da3a1af7bda0e2ba19e
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/op/OperatorIn.java
@@ -0,0 +1,61 @@
+package com.ql.util.express.instruction.op;
+
+import java.lang.reflect.Array;
+import java.util.List;
+
+import com.ql.util.express.Operator;
+
+public class OperatorIn extends Operator {
+ public OperatorIn(String aName) {
+ this.name = aName;
+ }
+
+ public OperatorIn(String aAliasName, String aName, String aErrorInfo) {
+ this.name = aName;
+ this.aliasName = aAliasName;
+ this.errorInfo = aErrorInfo;
+ }
+
+ public Object executeInner(Object[] list) throws Exception {
+ Object obj = list[0];
+ if (obj == null) {
+ // 对象为空,不能执行方法
+ String msg = "对象为空,不能执行方法:";
+ throw new Exception(msg + this.name);
+ } else if (((obj instanceof Number) || (obj instanceof String)) == false) {
+ String msg = "对象类型不匹配,只有数字和字符串类型才才能执行 in 操作,当前数据类型是:";
+ throw new Exception(msg + obj.getClass().getName());
+ } else if(list.length == 2 && (list[1].getClass().isArray() || list[1] instanceof List)){
+ if(obj.equals(list[1]) == true){
+ return true;
+ }else if(list[1].getClass().isArray()){
+ int len = Array.getLength(list[1]);
+ for(int i=0;i array = (List)list[1];
+ for(int i=0;i= 0) {
+ String[] list = split(s2, "%");
+ int index = 0;
+ for (int i = 0; i < list.length; i++) {
+ if (index >= s1.length()) {
+ result = false;
+ break;
+ }
+ index = s1.indexOf(list[i], index);
+ if (index < 0) {
+ result = false;
+ break;
+ }
+ index = index + 1;
+ }
+ } else if (s1.equals(s2))
+ result = true;
+ else
+ result = false;
+
+ return Boolean.valueOf(result);
+ }
+
+ public String[] split(String str, String s) {
+ int start = 0;
+ int end = -1;
+ String tmpStr = "";
+ ArrayList list = new ArrayList();
+ do {
+ end = str.indexOf(s, start);
+ if (end < 0)
+ tmpStr = str.substring(start);
+ else
+ tmpStr = str.substring(start, end);
+ if (tmpStr.length() > 0)
+ list.add(tmpStr);
+ start = end + 1;
+ if (start >= str.length())
+ break;
+ } while (end >= 0);
+ return (String[]) list.toArray(new String[0]);
+ }
+}
diff --git a/src/main/java/com/ql/util/express/instruction/op/OperatorMacro.java b/src/main/java/com/ql/util/express/instruction/op/OperatorMacro.java
new file mode 100644
index 0000000000000000000000000000000000000000..a3ed82dbf12c721d2fcc3037f5f0508843b85a0f
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/op/OperatorMacro.java
@@ -0,0 +1,26 @@
+package com.ql.util.express.instruction.op;
+
+import com.ql.util.express.ArraySwap;
+import com.ql.util.express.InstructionSetContext;
+import com.ql.util.express.OperateData;
+import com.ql.util.express.instruction.opdata.OperateDataAlias;
+import com.ql.util.express.instruction.opdata.OperateDataAttr;
+
+public class OperatorMacro extends OperatorBase {
+ public OperatorMacro(String aName) {
+ this.name = aName;
+ }
+ public OperatorMacro(String aAliasName, String aName, String aErrorInfo) {
+ this.name = aName;
+ this.aliasName = aAliasName;
+ this.errorInfo = aErrorInfo;
+ }
+
+ public OperateData executeInner(InstructionSetContext context, ArraySwap list) throws Exception {
+ String varName = (String)list.get(0).getObjectInner(context);
+ OperateDataAttr realAttr = (OperateDataAttr)list.get(1);
+ OperateDataAttr result = new OperateDataAlias(varName,realAttr);
+ context.addSymbol(varName, result);
+ return result;
+ }
+}
diff --git a/src/main/java/com/ql/util/express/instruction/op/OperatorMethod.java b/src/main/java/com/ql/util/express/instruction/op/OperatorMethod.java
new file mode 100644
index 0000000000000000000000000000000000000000..d0e4a70ba84f5a1bc52d566144975b6580e33728
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/op/OperatorMethod.java
@@ -0,0 +1,116 @@
+package com.ql.util.express.instruction.op;
+
+import java.lang.reflect.Method;
+
+import com.ql.util.express.ArraySwap;
+import com.ql.util.express.ExpressUtil;
+import com.ql.util.express.InstructionSetContext;
+import com.ql.util.express.OperateData;
+import com.ql.util.express.instruction.OperateDataCacheManager;
+import com.ql.util.express.instruction.opdata.OperateClass;
+import com.ql.util.express.instruction.opdata.OperateDataVirClass;
+import com.ql.util.express.parse.AppendingClassMethodManager;
+
+public class OperatorMethod extends OperatorBase {
+ String methodName;
+ public OperatorMethod() {
+ this.name ="MethodCall";
+ }
+ public OperatorMethod(String aMethodName) {
+ this.name ="MethodCall";
+ this.methodName = aMethodName;
+ }
+ static Class> ArrayClass = (new Object[]{}).getClass();
+
+ public OperateData executeInner(InstructionSetContext parent, ArraySwap list) throws Exception {
+ OperateData p0 = list.get(0);
+ Object obj = p0.getObject(parent);
+ if(obj instanceof OperateDataVirClass ){
+ OperateDataVirClass vClass = (OperateDataVirClass)obj;
+ OperateData[] parameters = new OperateData[list.length - 1];
+ for(int i=0;i< list.length -1;i++){
+ parameters[i] =list.get(i+1);
+ }
+ return vClass.callSelfFunction(this.methodName, parameters);
+ }
+
+ if (obj == null) {
+ // 对象为空,不能执行方法
+ String msg = "对象为空,不能执行方法:";
+ throw new Exception(msg + this.methodName);
+ } else {
+ Class>[] types = new Class[list.length - 1];
+ Class>[] orgiTypes = new Class[list.length - 1];
+
+ Object[] objs = new Object[list.length - 1];
+ Object tmpObj;
+ OperateData p;
+ for (int i = 0; i < types.length; i++) {
+ p = list.get(i+ 1);
+ tmpObj = p.getObject(parent);
+ types[i] = p.getType(parent);
+ orgiTypes[i] = p.getType(parent);
+ objs[i] = tmpObj;
+ }
+ AppendingClassMethodManager appendingClassMethodManager = parent.getExpressRunner().getAppendingClassMethodManager();
+
+ if(appendingClassMethodManager!=null) {
+ AppendingClassMethodManager.AppendingMethod appendingClassMethod = appendingClassMethodManager.getAppendingClassMethod(obj, this.methodName);
+ if (appendingClassMethod != null) {
+ return appendingClassMethodManager.invoke(appendingClassMethod, parent, list, null);
+ }
+ }
+ Method m = null;
+ if (p0 instanceof OperateClass) {// 调用静态方法
+ m = ExpressUtil.findMethodWithCache((Class>) obj, this.methodName,
+ types, true, true);
+ } else {
+ m = ExpressUtil.findMethodWithCache(obj.getClass(), this.methodName,
+ types, true, false);
+ }
+ if(m == null){
+ types = new Class[]{ArrayClass};
+ if (p0 instanceof OperateClass) {// 调用静态方法
+ m = ExpressUtil.findMethodWithCache((Class>) obj, methodName,
+ types, true, true);
+ } else {
+ m = ExpressUtil.findMethodWithCache(obj.getClass(), methodName,
+ types, true, false);
+ }
+ objs = new Object[]{objs};
+ }
+ if (m == null) {
+ StringBuilder s = new StringBuilder();
+ s.append("没有找到" + obj.getClass().getName() + "的方法:"
+ + methodName + "(");
+ for (int i = 0; i < orgiTypes.length; i++) {
+ if (i > 0)
+ s.append(",");
+ if(orgiTypes[i] == null){
+ s.append("null");
+ }else{
+ s.append(orgiTypes[i].getName());
+ }
+ }
+ s.append(")");
+ throw new Exception(s.toString());
+ }
+
+ if (p0 instanceof OperateClass) {// 调用静态方法
+ boolean oldA = m.isAccessible();
+ m.setAccessible(true);
+ tmpObj = m.invoke(null,ExpressUtil.transferArray(objs,m.getParameterTypes()));
+ m.setAccessible(oldA);
+ } else {
+ boolean oldA = m.isAccessible();
+ m.setAccessible(true);
+ tmpObj = m.invoke(obj, ExpressUtil.transferArray(objs,m.getParameterTypes()));
+ m.setAccessible(oldA);
+ }
+ return OperateDataCacheManager.fetchOperateData(tmpObj, m.getReturnType());
+ }
+ }
+ public String toString(){
+ return this.name + ":" + this.methodName;
+ }
+}
diff --git a/src/main/java/com/ql/util/express/instruction/op/OperatorMinMax.java b/src/main/java/com/ql/util/express/instruction/op/OperatorMinMax.java
new file mode 100644
index 0000000000000000000000000000000000000000..7a7903d53f4d6f2c13f16179e33a52cf92937424
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/op/OperatorMinMax.java
@@ -0,0 +1,38 @@
+package com.ql.util.express.instruction.op;
+
+import com.ql.util.express.Operator;
+
+public class OperatorMinMax extends Operator {
+ public OperatorMinMax(String name) {
+ this.name = name;
+ }
+
+ public Object executeInner(Object[] list) throws Exception {
+ if (list.length == 0){
+ throw new Exception("操作数异常");
+ }
+ Object result = list[0];
+
+ for (int i = 1; i < list.length; i++)
+ result = executeInner(result, list[i]);
+ return result;
+ }
+
+ public Object executeInner(Object op1,
+ Object op2) throws Exception {
+ Object result = null;
+ int compareResult = Operator.compareData(op1,op2);
+ if (this.name.equals("min")) {
+ if (compareResult < 0)
+ result = op1;
+ else
+ result = op2;
+ } else if (this.name.equals("max")) {
+ if (compareResult < 0)
+ result = op2;
+ else
+ result = op1;
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/com/ql/util/express/instruction/op/OperatorMultiDiv.java b/src/main/java/com/ql/util/express/instruction/op/OperatorMultiDiv.java
new file mode 100644
index 0000000000000000000000000000000000000000..bd6cc07639b913e131e30862fd6c4a8b842b02bd
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/op/OperatorMultiDiv.java
@@ -0,0 +1,30 @@
+package com.ql.util.express.instruction.op;
+
+import com.ql.util.express.Operator;
+import com.ql.util.express.OperatorOfNumber;
+
+public class OperatorMultiDiv extends Operator {
+ public OperatorMultiDiv(String name) {
+ this.name = name;
+ }
+
+ public Object executeInner(Object[] list) throws Exception {
+ return executeInner( list[0], list[1]);
+ }
+
+ public Object executeInner(Object op1,
+ Object op2) throws Exception {
+ Object obj = null;
+ if (this.getName().equals("*"))
+ obj = OperatorOfNumber.multiply(op1, op2,this.isPrecise);
+ else if (this.getName().equals("/"))
+ obj = OperatorOfNumber.divide(op1, op2,this.isPrecise);
+ else if (this.getName().equals("%"))
+ obj = OperatorOfNumber.modulo(op1, op2);
+ else if (this.getName().equals("mod"))
+ obj = OperatorOfNumber.modulo(op1, op2);
+
+ return obj;
+
+ }
+}
diff --git a/src/main/java/com/ql/util/express/instruction/op/OperatorNew.java b/src/main/java/com/ql/util/express/instruction/op/OperatorNew.java
new file mode 100644
index 0000000000000000000000000000000000000000..c79f0763d7dc00cc48b121fd48cbb08213ce4385
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/op/OperatorNew.java
@@ -0,0 +1,60 @@
+package com.ql.util.express.instruction.op;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+
+import com.ql.util.express.ArraySwap;
+import com.ql.util.express.ExpressUtil;
+import com.ql.util.express.InstructionSetContext;
+import com.ql.util.express.OperateData;
+import com.ql.util.express.instruction.OperateDataCacheManager;
+
+public class OperatorNew extends OperatorBase {
+ public OperatorNew(String aName) {
+ this.name = aName;
+ }
+
+ public OperateData executeInner(InstructionSetContext parent, ArraySwap list) throws Exception {
+ Class> obj = (Class>) list.get(0).getObject(parent);
+ if (obj.isArray()) {
+ Class> tmpClass = obj;
+ int dim = 0;
+ while (tmpClass.isArray()) {
+ tmpClass = tmpClass.getComponentType();
+ dim = dim + 1;
+ }
+ int[] dimLength = new int[dim];
+ for (int index = 0; index < dim; index++) {
+ dimLength[index] = ((Number) (list.get(index + 1).getObject(parent)))
+ .intValue();
+ }
+ return OperateDataCacheManager.fetchOperateData(Array.newInstance(tmpClass, dimLength), obj);
+ }
+ Class>[] types = new Class[list.length - 1];
+ Object[] objs = new Object[list.length - 1];
+ Object tmpObj;
+ for (int i = 0; i < types.length; i++) {
+ tmpObj = list.get(i + 1).getObject(parent);
+ types[i] = list.get(i + 1).getType(parent);
+ objs[i] = tmpObj;
+ }
+ Constructor> c = ExpressUtil.findConstructorWithCache(obj, types);
+
+ if (c == null) {
+ // "没有找到" + obj.getName() + "的构造方法:"
+ StringBuilder s = new StringBuilder();
+ s.append("没有找到" + obj.getName() + "的构造方法:" + obj.getName() + "(");
+ for (int i = 0; i < types.length; i++) {
+ if (i > 0){
+ s.append(",");
+ }
+ s.append(types[i].getName());
+ }
+ s.append(")");
+ throw new Exception(s.toString());
+ }
+
+ tmpObj = c.newInstance(objs);
+ return OperateDataCacheManager.fetchOperateData(tmpObj, obj);
+ }
+}
diff --git a/src/main/java/com/ql/util/express/instruction/op/OperatorNor.java b/src/main/java/com/ql/util/express/instruction/op/OperatorNor.java
new file mode 100644
index 0000000000000000000000000000000000000000..eaceb7451294670a0971fe70f2f69a8652e5d2dc
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/op/OperatorNor.java
@@ -0,0 +1,28 @@
+package com.ql.util.express.instruction.op;
+
+import com.ql.util.express.Operator;
+
+public class OperatorNor extends Operator {
+ public OperatorNor(String name) {
+ this.name = name;
+ }
+
+ public OperatorNor(String aAliasName, String aName, String aErrorInfo) {
+ this.name = aName;
+ this.aliasName = aAliasName;
+ this.errorInfo = aErrorInfo;
+ }
+
+ public Object executeInner(Object[] list) throws Exception {
+ return executeInner(list[0], list[1]);
+ }
+
+ public Object executeInner(Object op1, Object op2) throws Exception {
+
+ if (op1 != null) {
+ return op1;
+ } else {
+ return op2;
+ }
+ }
+}
diff --git a/src/main/java/com/ql/util/express/instruction/op/OperatorNot.java b/src/main/java/com/ql/util/express/instruction/op/OperatorNot.java
new file mode 100644
index 0000000000000000000000000000000000000000..1c5b2f40d5ea3c227fb125f94cbdc7b6ade78f5d
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/op/OperatorNot.java
@@ -0,0 +1,35 @@
+package com.ql.util.express.instruction.op;
+
+import com.ql.util.express.Operator;
+
+public class OperatorNot extends Operator {
+ public OperatorNot(String name) {
+ this.name = name;
+ }
+ public OperatorNot(String aAliasName, String aName, String aErrorInfo) {
+ this.name = aName;
+ this.aliasName = aAliasName;
+ this.errorInfo = aErrorInfo;
+ }
+ public Object executeInner(Object[] list) throws Exception {
+ return executeInner(list[0]);
+ }
+
+ public Object executeInner(Object op)
+ throws Exception {
+ Object result = null;
+ if (op == null){
+ throw new Exception("null 不能执行操作:" + this.getAliasName());
+ }
+ if (Boolean.class.equals(op.getClass()) == true) {
+ boolean r = !((Boolean) op).booleanValue();
+ result = Boolean.valueOf(r);
+ } else {
+ //
+ String msg = "没有定义类型" + op.getClass().getName() + " 的 " + this.name
+ + "操作";
+ throw new Exception(msg);
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/com/ql/util/express/instruction/op/OperatorNullOp.java b/src/main/java/com/ql/util/express/instruction/op/OperatorNullOp.java
new file mode 100644
index 0000000000000000000000000000000000000000..5356d7e9e4f52e70c16ccee35d3951f4c5e9aab8
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/op/OperatorNullOp.java
@@ -0,0 +1,29 @@
+package com.ql.util.express.instruction.op;
+
+import com.ql.util.express.ArraySwap;
+import com.ql.util.express.IExpressContext;
+import com.ql.util.express.InstructionSetContext;
+import com.ql.util.express.OperateData;
+
+
+/**
+ * 处理 ",","(",")",";"
+ */
+
+public class OperatorNullOp extends OperatorBase {
+ public OperatorNullOp(String name) {
+ this.name = name;
+ }
+ public OperatorNullOp(String aAliasName, String aName, String aErrorInfo) {
+ this.name = aName;
+ this.aliasName = aAliasName;
+ this.errorInfo = aErrorInfo;
+ }
+ public OperateData executeInner(InstructionSetContext parent, ArraySwap list) throws Exception {
+ return executeInner(parent);
+ }
+
+ public OperateData executeInner(IExpressContext parent) throws Exception {
+ return null;
+ }
+}
diff --git a/src/main/java/com/ql/util/express/instruction/op/OperatorOr.java b/src/main/java/com/ql/util/express/instruction/op/OperatorOr.java
new file mode 100644
index 0000000000000000000000000000000000000000..bcb68fdc9389980dcd3513c31da6d8dbe606f24d
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/op/OperatorOr.java
@@ -0,0 +1,44 @@
+package com.ql.util.express.instruction.op;
+
+import com.ql.util.express.Operator;
+
+public class OperatorOr extends Operator {
+ public OperatorOr(String name) {
+ this.name = name;
+ }
+ public OperatorOr(String aAliasName, String aName, String aErrorInfo) {
+ this.name = aName;
+ this.aliasName = aAliasName;
+ this.errorInfo = aErrorInfo;
+ }
+ public Object executeInner(Object[] list) throws Exception {
+ return executeInner(list[0], list[1]);
+ }
+
+ public Object executeInner(Object op1,
+ Object op2) throws Exception {
+ Object o1 = op1;
+ Object o2 = op2;
+ boolean r1 = false;
+ boolean r2= false;
+ if(o1 == null){
+ r1 = false;
+ }else if(o1 instanceof Boolean){
+ r1 = ((Boolean) o1).booleanValue();
+ }else{
+ String msg = "没有定义类型" + o1 + "和" + o2 + " 的 " + this.name + "操作";
+ throw new Exception(msg);
+ }
+ if(o2 == null){
+ r2 = false;
+ }else if(o2 instanceof Boolean){
+ r2 = ((Boolean) o2).booleanValue();
+ }else{
+ String msg = "没有定义类型" + o1 + "和" + o2 + " 的 " + this.name + "操作";
+ throw new Exception(msg);
+ }
+ boolean result = r1 || r2;
+ return Boolean.valueOf(result);
+
+ }
+}
diff --git a/src/main/java/com/ql/util/express/instruction/op/OperatorPrint.java b/src/main/java/com/ql/util/express/instruction/op/OperatorPrint.java
new file mode 100644
index 0000000000000000000000000000000000000000..9f704f4175af7e4c68707d489ca4143e980b320e
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/op/OperatorPrint.java
@@ -0,0 +1,23 @@
+package com.ql.util.express.instruction.op;
+
+import com.ql.util.express.Operator;
+
+public class OperatorPrint extends Operator {
+ public OperatorPrint(String name) {
+ this.name = name;
+ }
+ public OperatorPrint(String aAliasName, String aName, String aErrorInfo) {
+ this.name = aName;
+ this.aliasName = aAliasName;
+ this.errorInfo = aErrorInfo;
+ }
+ public Object executeInner(Object[] list) throws Exception {
+ if (list.length != 1 ){
+ throw new Exception("操作数异常,有且只能有一个操作数");
+ }
+ System.out.print(list[0]);
+ return null;
+ }
+
+
+}
diff --git a/src/main/java/com/ql/util/express/instruction/op/OperatorPrintln.java b/src/main/java/com/ql/util/express/instruction/op/OperatorPrintln.java
new file mode 100644
index 0000000000000000000000000000000000000000..989028c6432d6cbd5719b1cc21e1e1a6ec0fe634
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/op/OperatorPrintln.java
@@ -0,0 +1,23 @@
+package com.ql.util.express.instruction.op;
+
+import com.ql.util.express.Operator;
+
+public class OperatorPrintln extends Operator {
+ public OperatorPrintln(String name) {
+ this.name = name;
+ }
+ public OperatorPrintln(String aAliasName, String aName, String aErrorInfo) {
+ this.name = aName;
+ this.aliasName = aAliasName;
+ this.errorInfo = aErrorInfo;
+ }
+ public Object executeInner(Object[] list) throws Exception {
+ if (list.length != 1 ){
+ throw new Exception("操作数异常,有且只能有一个操作数");
+ }
+ System.out.println(list[0]);
+ return null;
+ }
+
+
+}
diff --git a/src/main/java/com/ql/util/express/instruction/op/OperatorReduce.java b/src/main/java/com/ql/util/express/instruction/op/OperatorReduce.java
new file mode 100644
index 0000000000000000000000000000000000000000..9f1c9149185f92c5f8a714d3b06283e197fff6bf
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/op/OperatorReduce.java
@@ -0,0 +1,19 @@
+package com.ql.util.express.instruction.op;
+
+import com.ql.util.express.ArraySwap;
+import com.ql.util.express.Operator;
+import com.ql.util.express.OperatorOfNumber;
+
+public class OperatorReduce extends Operator {
+ public OperatorReduce(String name) {
+ this.name = name;
+ }
+ public OperatorReduce(String aAliasName, String aName, String aErrorInfo) {
+ this.name = aName;
+ this.aliasName = aAliasName;
+ this.errorInfo = aErrorInfo;
+ }
+ public Object executeInner(Object[] list) throws Exception {
+ return OperatorOfNumber.subtract(list[0], list[1],this.isPrecise);
+ }
+}
diff --git a/src/main/java/com/ql/util/express/instruction/op/OperatorRound.java b/src/main/java/com/ql/util/express/instruction/op/OperatorRound.java
new file mode 100644
index 0000000000000000000000000000000000000000..560ef3ff1f1540e130e186da4d6f769eb0fd5a4b
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/op/OperatorRound.java
@@ -0,0 +1,20 @@
+package com.ql.util.express.instruction.op;
+
+import com.ql.util.express.Operator;
+import com.ql.util.express.OperatorOfNumber;
+
+public class OperatorRound extends Operator {
+ public OperatorRound(String name) {
+ this.name = name;
+ }
+
+ public Object executeInner(Object[] list) throws Exception {
+ return executeInner(list[0], list[1]);
+ }
+
+ public Object executeInner(Object op1,Object op2) throws Exception {
+ double r = OperatorOfNumber.round(
+ ((Number) op1).doubleValue(), ((Number) op2).intValue());
+ return new Double(r);
+ }
+}
diff --git a/src/main/java/com/ql/util/express/instruction/op/OperatorSelfDefineClassFunction.java b/src/main/java/com/ql/util/express/instruction/op/OperatorSelfDefineClassFunction.java
new file mode 100644
index 0000000000000000000000000000000000000000..9cf33e310198a84d3f4af1c3981e254891af6163
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/op/OperatorSelfDefineClassFunction.java
@@ -0,0 +1,105 @@
+package com.ql.util.express.instruction.op;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import com.ql.util.express.*;
+import com.ql.util.express.instruction.OperateDataCacheManager;
+
+/**
+ * 用户自定义的函数操作
+ * @author qhlhl2010@gmail.com
+ *
+ */
+public class OperatorSelfDefineClassFunction extends OperatorBase implements CanClone{
+ String functionName;
+ String[] parameterTypes;
+ Class>[] parameterClasses ;
+ Class> operClass;
+ Object operInstance;
+ transient Method method;
+ boolean isReturnVoid;
+ boolean maybeDynamicParams;
+
+ public OperatorSelfDefineClassFunction(String aOperName,String aClassName, String aFunctionName,
+ Class>[] aParameterClassTypes,String[] aParameterDesc,String[] aParameterAnnotation,String aErrorInfo) throws Exception {
+ if (errorInfo != null && errorInfo.trim().length() == 0) {
+ errorInfo = null;
+ }
+ this.name = aOperName;
+ this.errorInfo = aErrorInfo;
+ this.functionName = aFunctionName;
+ this.parameterClasses = aParameterClassTypes;
+ this.parameterTypes = new String[aParameterClassTypes.length];
+ this.operDataDesc = aParameterDesc;
+ this.operDataAnnotation = aParameterAnnotation;
+ for(int i=0;i[] parameterClasses ;
+ transient Method method;
+ boolean isReturnVoid;
+ boolean maybeDynamicParams;
+
+ public OperatorSelfDefineServiceFunction(String aOperName,
+ Object aServiceObject, String aFunctionName,
+ Class>[] aParameterClassTypes,String[] aParameterDesc,String[] aParameterAnnotation, String aErrorInfo) throws Exception {
+ if (errorInfo != null && errorInfo.trim().length() == 0) {
+ errorInfo = null;
+ }
+ this.name = aOperName;
+ this.errorInfo = aErrorInfo;
+ this.serviceObject = aServiceObject;
+ this.functionName = aFunctionName;
+ this.parameterClasses = aParameterClassTypes;
+ this.operDataDesc = aParameterDesc;
+ this.operDataAnnotation = aParameterAnnotation;
+ this.parameterTypes = new String[this.parameterClasses.length];
+ for (int i = 0; i < this.parameterClasses.length; i++) {
+ this.parameterTypes[i] = this.parameterClasses[i].getName();
+ }
+ Class> operClass = serviceObject.getClass();
+ method = operClass.getMethod(functionName, parameterClasses);
+ this.isReturnVoid = method.getReturnType().equals(void.class);
+ this.maybeDynamicParams = DynamicParamsUtil.maybeDynamicParams(parameterClasses);
+ }
+
+ public OperatorSelfDefineServiceFunction(String aOperName,Object aServiceObject, String aFunctionName,
+ String[] aParameterTypes,String[] aParameterDesc,String[] aParameterAnnotation,String aErrorInfo) throws Exception {
+
+ if (errorInfo != null && errorInfo.trim().length() == 0) {
+ errorInfo = null;
+ }
+ this.name = aOperName;
+ this.errorInfo = aErrorInfo;
+ this.serviceObject = aServiceObject;
+ this.functionName = aFunctionName;
+ this.parameterTypes = aParameterTypes;
+ this.operDataDesc = aParameterDesc;
+ this.operDataAnnotation = aParameterAnnotation;
+ this.parameterClasses = new Class[this.parameterTypes.length];
+ for(int i=0;i operClass = serviceObject.getClass();
+ method = operClass.getMethod(functionName,parameterClasses);
+ this.maybeDynamicParams = DynamicParamsUtil.maybeDynamicParams(parameterClasses);
+ }
+
+ public OperatorBase cloneMe(String opName, String errorInfo)
+ throws Exception {
+ OperatorBase result = new OperatorSelfDefineServiceFunction(opName,
+ this.serviceObject, this.functionName, this.parameterClasses,
+ this.operDataDesc, this.operDataAnnotation, errorInfo);
+ return result;
+ }
+ public OperateData executeInner(InstructionSetContext context, ArraySwap list) throws Exception {
+ Object[] parameres = DynamicParamsUtil.transferDynamicParams(context, list, parameterClasses,this.maybeDynamicParams);
+ Object obj = this.getMethod().invoke(this.serviceObject,ExpressUtil.transferArray(parameres,parameterClasses));
+ if(obj != null){
+ return OperateDataCacheManager.fetchOperateData(obj,obj.getClass());
+ }
+ if(this.isReturnVoid == true){
+ return OperateDataCacheManager.fetchOperateDataAttr("null", void.class);
+ }else{
+ return OperateDataCacheManager.fetchOperateDataAttr("null", null);
+ }
+ }
+
+ private Method getMethod() throws NoSuchMethodException {
+
+ if(this.method!=null){
+ return this.method;
+ }
+ Class> operClass = serviceObject.getClass();
+ this.method = operClass.getMethod(functionName, parameterClasses);
+ return this.method;
+ }
+}
diff --git a/src/main/java/com/ql/util/express/instruction/opdata/OperateClass.java b/src/main/java/com/ql/util/express/instruction/opdata/OperateClass.java
new file mode 100644
index 0000000000000000000000000000000000000000..1a2ec29862bf8b398a64fe7638d07974482ccf58
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/opdata/OperateClass.java
@@ -0,0 +1,34 @@
+package com.ql.util.express.instruction.opdata;
+
+import com.ql.util.express.InstructionSetContext;
+import com.ql.util.express.OperateData;
+
+public class OperateClass extends OperateData {
+ private String name;
+ private Class> m_class;
+ public OperateClass(String name, Class> aClass) {
+ super(null,null);
+ this.name = name;
+ this.m_class = aClass;
+ }
+ public void toResource(StringBuilder builder,int level){
+ builder.append(this.name);
+ }
+ public String toString() {
+ return "Class:" + name;
+ // return name;
+ }
+ public Class> getVarClass(){
+ return this.m_class;
+ }
+ public void reset(String aName,Class> newClass){
+ this.name = aName;
+ this.m_class = newClass;
+ }
+ public Object getObjectInner(InstructionSetContext parent) {
+ return m_class;
+ }
+ public String getName(){
+ return this.name;
+ }
+}
diff --git a/src/main/java/com/ql/util/express/instruction/opdata/OperateDataAlias.java b/src/main/java/com/ql/util/express/instruction/opdata/OperateDataAlias.java
new file mode 100644
index 0000000000000000000000000000000000000000..21e9bc93fa0c25034ad34bf504f615f65c44f996
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/opdata/OperateDataAlias.java
@@ -0,0 +1,37 @@
+package com.ql.util.express.instruction.opdata;
+
+import com.ql.util.express.InstructionSetContext;
+
+public class OperateDataAlias extends OperateDataAttr {
+ OperateDataAttr realAttr;
+ public OperateDataAlias(String aName,OperateDataAttr aRealAttr) {
+ super(aName,null);
+ this.realAttr = aRealAttr;
+ }
+ public String toString() {
+ try {
+ return this.name + "[alias=" + this.realAttr.name+"]";
+ } catch (Exception ex) {
+ return ex.getMessage();
+ }
+ }
+ public Object getObjectInner(InstructionSetContext context) {
+ try {
+ return realAttr.getObject(context);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public Class> getType(InstructionSetContext context) throws Exception {
+ return realAttr.getType(context);
+ }
+
+ public void setObject(InstructionSetContext context, Object object) {
+ try {
+ realAttr.setObject(context, object);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/src/main/java/com/ql/util/express/instruction/opdata/OperateDataArrayItem.java b/src/main/java/com/ql/util/express/instruction/opdata/OperateDataArrayItem.java
new file mode 100644
index 0000000000000000000000000000000000000000..95aa829662568ab6c5b20b7c8a1ae86e1dfd56a8
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/opdata/OperateDataArrayItem.java
@@ -0,0 +1,54 @@
+package com.ql.util.express.instruction.opdata;
+
+import java.lang.reflect.Array;
+
+import com.ql.util.express.InstructionSetContext;
+import com.ql.util.express.OperateData;
+
+public class OperateDataArrayItem extends OperateDataAttr {
+ OperateData arrayObject;
+ int index;
+ public OperateDataArrayItem(OperateData aArrayObject,int aIndex) {
+ super("array[" + aArrayObject +"," + aIndex +"]",null);
+ this.arrayObject = aArrayObject;
+ this.index = aIndex;
+ }
+ public void initialDataArrayItem(OperateData aArrayObject,int aIndex){
+ super.initialDataAttr("array[" + aArrayObject +"," + aIndex +"]",null);
+ this.arrayObject = aArrayObject;
+ this.index = aIndex;
+ }
+ public void clearDataArrayItem(){
+ super.clearDataAttr();
+ this.arrayObject = null;
+ this.index = -1;
+ }
+ public void toResource(StringBuilder builder,int level){
+ builder.append(this.index);
+ }
+ public Class> getType(InstructionSetContext context) throws Exception {
+ return this.arrayObject.getObject(context).getClass();
+ }
+ public Object getObjectInner(InstructionSetContext context){
+ try {
+ return Array.get(this.arrayObject.getObject(context),this.index);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void setObject(InstructionSetContext context, Object value) {
+ try {
+ Array.set(this.arrayObject.getObject(context), this.index, value);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
+
+
+
+
+
+
+
diff --git a/src/main/java/com/ql/util/express/instruction/opdata/OperateDataAttr.java b/src/main/java/com/ql/util/express/instruction/opdata/OperateDataAttr.java
new file mode 100644
index 0000000000000000000000000000000000000000..f9f2d8c2c4a6ca835a5bb76bbede337ea498d309
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/opdata/OperateDataAttr.java
@@ -0,0 +1,80 @@
+package com.ql.util.express.instruction.opdata;
+
+import com.ql.util.express.ExpressUtil;
+import com.ql.util.express.InstructionSetContext;
+import com.ql.util.express.OperateData;
+
+
+public class OperateDataAttr extends OperateData {
+ protected String name;
+ public OperateDataAttr(String aName,Class> aType) {
+ super(null,aType);
+ this.name = aName;
+ }
+ public void initialDataAttr(String aName, Class> aType) {
+ super.initial(null, aType);
+ this.name = aName;
+ }
+ public void clearDataAttr(){
+ super.clear();
+ this.name = null;
+ }
+ public void setDefineType(Class> orgiType){
+ this.type = orgiType;
+ }
+ public Class> getDefineType(){
+ return this.type;
+ }
+ public String getName(){
+ return name;
+ }
+ public void toResource(StringBuilder builder,int level){
+ builder.append(this.name);
+ }
+ public String toString() {
+ try {
+ String str ="";
+ if(this.type == null){
+ str = name;
+ }else{
+ str = name + "[" + ExpressUtil.getClassName(this.type) + "]" ;
+ }
+ return str;
+ } catch (Exception ex) {
+ return ex.getMessage();
+ }
+ }
+ public Object getObjectInner(InstructionSetContext context) throws Exception {
+ if (this.name.equalsIgnoreCase("null")) {
+ return null;
+ }
+ if (context == null) {
+ throw new RuntimeException("没有设置表达式计算的上下文,不能获取属性:\"" + this.name
+ + "\"请检查表达式");
+ }
+ try {
+ return context.get(this.name);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public Class> getType(InstructionSetContext context) throws Exception {
+ if(this.type != null){
+ return this.type;
+ }
+ Object obj = context.get(name);
+ if (obj == null)
+ return null;
+ else
+ return obj.getClass();
+ }
+
+ public void setObject(InstructionSetContext parent, Object object) throws Exception {
+ try {
+ parent.put(this.name, object);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
diff --git a/src/main/java/com/ql/util/express/instruction/opdata/OperateDataField.java b/src/main/java/com/ql/util/express/instruction/opdata/OperateDataField.java
new file mode 100644
index 0000000000000000000000000000000000000000..dc2cb597045ae95cb45affcbf45d96ffb1dd10d2
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/opdata/OperateDataField.java
@@ -0,0 +1,105 @@
+package com.ql.util.express.instruction.opdata;
+
+import com.ql.util.express.ExpressUtil;
+import com.ql.util.express.InstructionSetContext;
+import com.ql.util.express.parse.AppendingClassFieldManager;
+import com.ql.util.express.parse.AppendingClassMethodManager;
+
+public class OperateDataField extends OperateDataAttr {
+ Object fieldObject;
+ String orgiFieldName;
+
+ public OperateDataField(Object aFieldObject,String aFieldName) {
+ super(null,null);
+ if(aFieldObject == null){
+ this.name = "没有初始化的Field";
+ }else{
+ this.name = aFieldObject.getClass().getName() + "." + aFieldName;
+ }
+ this.fieldObject = aFieldObject;
+ this.orgiFieldName =aFieldName;
+ }
+
+ public void initialDataField(Object aFieldObject,String aFieldName){
+ super.initialDataAttr(null, null);
+ this.name = aFieldObject.getClass().getName() + "." + aFieldName;
+ this.fieldObject = aFieldObject;
+ this.orgiFieldName = aFieldName;
+ }
+ public void clearDataField(){
+ super.clearDataAttr();
+ this.name = null;
+ this.fieldObject = null;
+ this.orgiFieldName = null;
+ }
+ public String getName(){
+ return name;
+ }
+ public String toString() {
+ try {
+ return name;
+ } catch (Exception ex) {
+ return ex.getMessage();
+ }
+ }
+
+ public Object transferFieldName(InstructionSetContext context,String oldName){
+ if (context.isSupportDynamicFieldName() == false) {
+ return oldName;
+ } else {
+ try {
+ OperateDataAttr o = (OperateDataAttr) context
+ .findAliasOrDefSymbol(oldName);
+ if (o != null) {
+ return o.getObject(context);
+ } else {
+ return oldName;
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ public Object getObjectInner(InstructionSetContext context) throws Exception {
+
+ AppendingClassFieldManager appendingClassFieldManager = context.getExpressRunner().getAppendingClassFieldManager();
+
+ if(appendingClassFieldManager!=null) {
+ AppendingClassFieldManager.AppendingField appendingField = appendingClassFieldManager.getAppendingClassField(this.fieldObject, this.orgiFieldName);
+ if (appendingField != null) {
+ return appendingClassFieldManager.invoke(appendingField, context, this.fieldObject, null);
+ }
+ }
+ //如果能找到aFieldName的定义,则再次运算
+ if(this.fieldObject instanceof OperateDataVirClass){
+ return ((OperateDataVirClass)this.fieldObject).getValue(transferFieldName(context,this.orgiFieldName));
+ }else{
+ return ExpressUtil.getProperty(this.fieldObject,transferFieldName(context,this.orgiFieldName));
+ }
+ }
+
+ public Class> getType(InstructionSetContext context) throws Exception {
+ AppendingClassFieldManager appendingClassFieldManager = context.getExpressRunner().getAppendingClassFieldManager();
+
+ if(appendingClassFieldManager!=null) {
+ AppendingClassFieldManager.AppendingField appendingField = appendingClassFieldManager.getAppendingClassField(this.fieldObject, this.orgiFieldName);
+ if (appendingField != null) {
+ return appendingField.returnType;
+ }
+ }
+ if(this.fieldObject instanceof OperateDataVirClass){
+ return ((OperateDataVirClass)this.fieldObject).getValueType(transferFieldName(context,this.orgiFieldName));
+ }else{
+ return ExpressUtil.getPropertyClass(this.fieldObject,transferFieldName(context,this.orgiFieldName));
+ }
+ }
+
+ public void setObject(InstructionSetContext context, Object value) throws Exception{
+ if(this.fieldObject instanceof OperateDataVirClass){
+ ((OperateDataVirClass)this.fieldObject).setValue(transferFieldName(context,this.orgiFieldName).toString(),value);
+ }else{
+ ExpressUtil.setProperty(fieldObject, transferFieldName(context,this.orgiFieldName), value);
+ }
+
+ }
+}
diff --git a/src/main/java/com/ql/util/express/instruction/opdata/OperateDataKeyValue.java b/src/main/java/com/ql/util/express/instruction/opdata/OperateDataKeyValue.java
new file mode 100644
index 0000000000000000000000000000000000000000..095b90d42f28fbf318ac568bf0bd8044fcf1bbce
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/opdata/OperateDataKeyValue.java
@@ -0,0 +1,50 @@
+package com.ql.util.express.instruction.opdata;
+
+import com.ql.util.express.InstructionSetContext;
+import com.ql.util.express.OperateData;
+
+public class OperateDataKeyValue extends OperateData {
+ OperateData key;
+ OperateData value;
+
+ public OperateDataKeyValue(OperateData aKey, OperateData aValue) {
+ super(null, null);
+ this.key = aKey;
+ this.value = aValue;
+ }
+ public void initialDataKeyValue(OperateData aKey, OperateData aValue){
+ super.initial(null, null);
+ this.key = aKey;
+ this.value = aValue;
+ }
+ public void clearDataKeyValue(){
+ super.clear();
+ this.key = null;
+ this.value = null;
+ }
+ public OperateData getKey() {
+ return key;
+ }
+
+ public OperateData getValue() {
+ return value;
+ }
+
+ public String toString() {
+ return this.key + ":" + this.value;
+ }
+
+ public Object getObjectInner(InstructionSetContext context) {
+ throw new RuntimeException("没有实现方法:getObjectInner");
+ }
+
+ public Class> getType(InstructionSetContext context)
+ throws Exception {
+ throw new RuntimeException("没有实现方法:getType");
+ }
+
+ public void setObject(InstructionSetContext parent,
+ Object object) {
+ throw new RuntimeException("没有实现方法:setObject");
+ }
+}
diff --git a/src/main/java/com/ql/util/express/instruction/opdata/OperateDataLocalVar.java b/src/main/java/com/ql/util/express/instruction/opdata/OperateDataLocalVar.java
new file mode 100644
index 0000000000000000000000000000000000000000..0b122eceb527fa87d62d3165c5b02222f95c0922
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/opdata/OperateDataLocalVar.java
@@ -0,0 +1,41 @@
+package com.ql.util.express.instruction.opdata;
+
+import com.ql.util.express.InstructionSetContext;
+
+
+
+public class OperateDataLocalVar extends OperateDataAttr {
+ public OperateDataLocalVar(String name,Class> type) {
+ super(name,type);
+ }
+
+ public void initialDataLocalVar(String name,Class> type){
+ super.initialDataAttr(name, type);
+ }
+ public void clearDataLocalVar(){
+ super.clear();
+ }
+ public String toString() {
+ try {
+ return name +":localVar";
+ } catch (Exception ex) {
+ return ex.getMessage();
+ }
+ }
+
+ public Object getObjectInner(InstructionSetContext context) {
+ try {
+ return this.dataObject;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public Class> getType(InstructionSetContext context) throws Exception {
+ return this.type;
+ }
+
+ public void setObject(InstructionSetContext parent, Object value) {
+ this.dataObject = value;
+ }
+}
diff --git a/src/main/java/com/ql/util/express/instruction/opdata/OperateDataVirClass.java b/src/main/java/com/ql/util/express/instruction/opdata/OperateDataVirClass.java
new file mode 100644
index 0000000000000000000000000000000000000000..4b21c60e5dc1e4744529db11f8b91dfd9a314676
--- /dev/null
+++ b/src/main/java/com/ql/util/express/instruction/opdata/OperateDataVirClass.java
@@ -0,0 +1,136 @@
+package com.ql.util.express.instruction.opdata;
+
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+
+import com.ql.util.express.InstructionSet;
+import com.ql.util.express.InstructionSetContext;
+import com.ql.util.express.InstructionSetRunner;
+import com.ql.util.express.OperateData;
+import com.ql.util.express.instruction.OperateDataCacheManager;
+
+
+/**
+ * 虚拟Class的内存对象
+ * @author xuannan
+ *
+ */
+public class OperateDataVirClass extends OperateDataAttr{
+ /**
+ * 虚拟Class的数据上下文
+ */
+ InstructionSetContext context;
+ /**
+ * 虚拟类的指令集合
+ */
+ InstructionSet virClassInstructionSet;
+
+ boolean isTrace;
+ Log log;
+ public OperateDataVirClass(String name){
+ super(name,null);
+ }
+ public void initialInstance(InstructionSetContext parent,OperateData[] parameters,
+ List errorList,boolean aIsTrace,Log aLog) throws Exception {
+ this.isTrace = aIsTrace;
+ this.log = aLog;
+ this.context = OperateDataCacheManager.fetchInstructionSetContext(false,
+ parent.getExpressRunner(),parent,parent.getExpressLoader(),parent.isSupportDynamicFieldName());
+ Object functionSet = parent.getSymbol(this.name);
+ if (functionSet == null || functionSet instanceof InstructionSet == false) {
+ throw new Exception("没有找到自定义对象\"" + this.name + "\"");
+ }
+ this.virClassInstructionSet = (InstructionSet)functionSet;
+
+ OperateDataLocalVar[] vars = virClassInstructionSet.getParameters();
+ for(int i=0;i getValueType(Object name) throws Exception{
+ Object o = this.context.findAliasOrDefSymbol(name.toString());
+ if(o instanceof OperateData){
+ return ((OperateData)o).getType(context);
+ }else{
+ throw new Exception("不支持的数据类型:" + o.getClass().getName());
+ }
+ }
+ public Object getObjectInner(InstructionSetContext context) {
+ return this;
+ }
+
+ public Class> getType(InstructionSetContext context) throws Exception {
+ return this.getClass();
+ }
+
+ public void setObject(InstructionSetContext parent, Object object) {
+ throw new RuntimeException("不支持的方法");
+ }
+
+ public String toString(){
+ return "VClass[" + this.name+"]";
+ }
+}
diff --git a/src/main/java/com/ql/util/express/match/IDataNode.java b/src/main/java/com/ql/util/express/match/IDataNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..78727d6d2f058c96d51693f8309ee3d8c7b63967
--- /dev/null
+++ b/src/main/java/com/ql/util/express/match/IDataNode.java
@@ -0,0 +1,16 @@
+package com.ql.util.express.match;
+
+
+
+public interface IDataNode {
+ public void setNodeType(INodeType type);
+ public void setTreeType(INodeType findNodeType);
+ public INodeType getNodeType();
+ public INodeType getTreeType();
+
+ public void addLeftChild(IDataNode ref);
+ public IDataNode createExpressNode(INodeType aType,String aValue) throws Exception;
+
+ public String getValue();
+ public void setObjectValue(Object value);
+}
diff --git a/src/main/java/com/ql/util/express/match/INodeType.java b/src/main/java/com/ql/util/express/match/INodeType.java
new file mode 100644
index 0000000000000000000000000000000000000000..a3166887de28020d70d325d69e96b4973b279724
--- /dev/null
+++ b/src/main/java/com/ql/util/express/match/INodeType.java
@@ -0,0 +1,13 @@
+package com.ql.util.express.match;
+
+
+/**
+ * 匹配类型
+ * @author xuannan
+ *
+ */
+public interface INodeType {
+ public String getName();
+ public INodeTypeManager getManager();
+ public QLPatternNode getPatternNode();
+}
diff --git a/src/main/java/com/ql/util/express/match/INodeTypeManager.java b/src/main/java/com/ql/util/express/match/INodeTypeManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..e301349955858e9cee6cd356421a1831add01d83
--- /dev/null
+++ b/src/main/java/com/ql/util/express/match/INodeTypeManager.java
@@ -0,0 +1,5 @@
+package com.ql.util.express.match;
+
+public interface INodeTypeManager {
+ public INodeType findNodeType(String name);
+}
diff --git a/src/main/java/com/ql/util/express/match/NodeTypeManagerTestImpl.java b/src/main/java/com/ql/util/express/match/NodeTypeManagerTestImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..416f86ea2b9a5030390afc129731f2ed7e523940
--- /dev/null
+++ b/src/main/java/com/ql/util/express/match/NodeTypeManagerTestImpl.java
@@ -0,0 +1,28 @@
+package com.ql.util.express.match;
+
+public class NodeTypeManagerTestImpl implements INodeTypeManager {
+
+ public INodeType findNodeType(String name) {
+ return new TestNodeTypeImpl(name);
+ }
+
+}
+
+class TestNodeTypeImpl implements INodeType{
+ String name;
+ public TestNodeTypeImpl(String aName){
+ this.name = aName;
+ }
+ public String getName() {
+ return this.name;
+ }
+
+ public INodeTypeManager getManager() {
+ throw new RuntimeException("没有实现的方法");
+ }
+
+ @Override
+ public QLPatternNode getPatternNode() {
+ throw new RuntimeException("没有实现的方法");
+ }
+}
diff --git a/src/main/java/com/ql/util/express/match/QLMatchResult.java b/src/main/java/com/ql/util/express/match/QLMatchResult.java
new file mode 100644
index 0000000000000000000000000000000000000000..2c26418de03c19ea36a853f0ea923eb93497bcde
--- /dev/null
+++ b/src/main/java/com/ql/util/express/match/QLMatchResult.java
@@ -0,0 +1,35 @@
+package com.ql.util.express.match;
+
+import java.util.List;
+
+public class QLMatchResult {
+ protected List matchs;
+ protected int matchLastIndex;
+ public INodeType statementNodeType;
+ public QLMatchResult(List aList,int aIndex){
+ this.matchLastIndex = aIndex;
+ this.matchs = aList;
+ }
+
+ public String toString(){
+ StringBuilder builder = new StringBuilder();
+ for(QLMatchResultTree item:matchs){
+ item.printNode(builder,1);
+ }
+ return builder.toString();
+ }
+ public List getMatchs() {
+ return matchs;
+ }
+
+ public void setMatchs(List matchs) {
+ this.matchs = matchs;
+ }
+ public int getMatchLastIndex() {
+ return matchLastIndex;
+ }
+
+ public void setMatchLastIndex(int matchLastIndex) {
+ this.matchLastIndex = matchLastIndex;
+ }
+ }
diff --git a/src/main/java/com/ql/util/express/match/QLMatchResultTree.java b/src/main/java/com/ql/util/express/match/QLMatchResultTree.java
new file mode 100644
index 0000000000000000000000000000000000000000..4e7a1cfdcb2b70cc7431a3e7e14cf6a804570ba9
--- /dev/null
+++ b/src/main/java/com/ql/util/express/match/QLMatchResultTree.java
@@ -0,0 +1,96 @@
+package com.ql.util.express.match;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class QLMatchResultTree{
+ INodeType matchNodeType;
+ IDataNode ref;
+
+ INodeType targetNodeType;
+ private List left;
+ private List right;
+
+ public QLMatchResultTree(INodeType aNodeType,IDataNode aRef,INodeType aTargetNodeType){
+ this(aNodeType,aRef);
+ this.targetNodeType = aTargetNodeType;
+ }
+ public QLMatchResultTree(INodeType aNodeType,IDataNode aRef){
+ this.matchNodeType = aNodeType;
+ this.ref = aRef;
+ }
+ public IDataNode getRef() {
+ return ref;
+ }
+ public List getLeft(){
+ return this.left;
+ }
+ public void addLeft(QLMatchResultTree node){
+ if(this.left == null){
+ this.left = new ArrayList();
+ }
+ this.left.add(node);
+ }
+ public void addLeftAll(List list){
+ if(this.left == null){
+ this.left = new ArrayList();
+ }
+ this.left.addAll(list);
+ }
+
+ public void addRightAll(List list){
+ if(this.right == null){
+ this.right = new ArrayList();
+ }
+ this.right.addAll(list);
+ }
+ public IDataNode transferExpressNodeType(IDataNode sourceNode,INodeType targetType){
+ sourceNode.setNodeType(targetType);
+ if(targetType == targetType.getManager().findNodeType("CONST_STRING")){
+ sourceNode.setObjectValue(sourceNode.getValue());
+ sourceNode.setTreeType(targetType.getManager().findNodeType("CONST"));
+ }
+ return sourceNode;
+ }
+ public void buildExpressNodeTree(){
+ if(this.targetNodeType != null){
+ transferExpressNodeType(this.ref,this.targetNodeType);
+ }
+ if(this.left != null){
+ for (QLMatchResultTree item : left) {
+ this.ref.addLeftChild(item.ref);
+ item.buildExpressNodeTree();
+ }
+ }
+ if (this.right != null) {
+ for (QLMatchResultTree item : right) {
+ this.ref.addLeftChild(item.ref);
+ item.buildExpressNodeTree();
+ }
+ }
+ }
+ public String toString(){
+ StringBuilder builder = new StringBuilder();
+ printNode(builder,1);
+ return builder.toString();
+ }
+
+ public void printNode(StringBuilder builder, int level) {
+ builder.append(level + ":");
+ for (int i = 0; i < level; i++) {
+ builder.append(" ");
+ }
+ builder.append(ref.getValue() + ":" + this.matchNodeType.getName())
+ .append("\n");
+ if (this.left != null) {
+ for (QLMatchResultTree item : this.left) {
+ item.printNode(builder, level + 1);
+ }
+ }
+ if (this.right != null) {
+ for (QLMatchResultTree item : this.right) {
+ item.printNode(builder, level + 1);
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/ql/util/express/match/QLPattern.java b/src/main/java/com/ql/util/express/match/QLPattern.java
new file mode 100644
index 0000000000000000000000000000000000000000..a57306e0d68eb1dda5fb688d08d6747eb2bfb523
--- /dev/null
+++ b/src/main/java/com/ql/util/express/match/QLPattern.java
@@ -0,0 +1,213 @@
+package com.ql.util.express.match;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class QLPattern {
+
+ private static final Log log = LogFactory.getLog(QLPattern.class);
+
+ public static QLPatternNode createPattern(INodeTypeManager nodeTypeManager,String name,String pattern) throws Exception{
+ return new QLPatternNode(nodeTypeManager,name,pattern);
+ }
+ public static QLMatchResult findMatchStatement(INodeTypeManager aManager,QLPatternNode pattern ,List extends IDataNode> nodes,int point) throws Exception{
+ AtomicLong maxMatchPoint = new AtomicLong();
+ QLMatchResult result = findMatchStatementWithAddRoot(aManager,pattern,nodes,point,true,maxMatchPoint);
+ if(result == null || result.matchs.size() == 0){
+ throw new Exception("程序错误,不满足语法规范,没有匹配到合适的语法,最大匹配致[0:" + (maxMatchPoint.longValue()-1) +"]");
+ }else if(result != null && result.matchs.size() != 1){
+ throw new Exception("程序错误,不满足语法规范,必须有一个根节点:" + pattern + ",最大匹配致[0:" + (maxMatchPoint.longValue()-1) +"]");
+ }
+ return result;
+ }
+ private static QLMatchResult findMatchStatementWithAddRoot(INodeTypeManager aManager,QLPatternNode pattern ,List extends IDataNode> nodes,int point,boolean isRoot,AtomicLong maxMatchPoint) throws Exception{
+ QLMatchResult result = null;
+ List tempList = null;
+ int count = 0;
+ int lastPoint = point;
+ while(true){
+ QLMatchResult tempResult = null;
+ if (pattern.matchMode == MatchMode.DETAIL) {
+ tempResult = matchDetailOneTime(aManager,pattern,nodes, lastPoint,maxMatchPoint);
+ }else if (pattern.matchMode == MatchMode.AND) {
+ tempResult = matchAndOneTime(aManager,pattern,nodes, lastPoint,maxMatchPoint);
+ }else if (pattern.matchMode == MatchMode.OR) {
+ tempResult = matchOrOneTime(aManager,pattern,nodes, lastPoint,maxMatchPoint);
+ }else{
+ throw new Exception("不正确的类型:" + pattern.matchMode.toString());
+ }
+ if(tempResult == null){
+ if(count >= pattern.minMatchNum && count <=pattern.maxMatchNum){
+ //正确匹配
+ if(tempList == null){
+ tempList = new ArrayList();
+ }
+ result = new QLMatchResult(tempList,lastPoint);
+ }else{
+ result = null;
+ }
+ break;
+ }else{
+ if(tempList == null){
+ tempList = new ArrayList();
+ }
+ lastPoint = tempResult.matchLastIndex;
+ if(pattern.isTreeRoot == true){
+ if(tempResult.matchs.size() > 1){
+ throw new Exception("根节点的数量必须是1");
+ }
+ if(tempList.size() == 0){
+ tempList.addAll(tempResult.matchs);
+ }else{
+ tempResult.matchs.get(0).addLeftAll(tempList);
+ tempList = tempResult.matchs;
+ }
+ }else{
+ tempList.addAll(tempResult.matchs);
+ }
+ }
+ count = count + 1;
+ if(count == pattern.maxMatchNum){
+ result = new QLMatchResult(tempList,lastPoint);
+ break;
+ }
+ }
+ if(result != null && pattern.isSkip == true){
+ //忽略跳过所有匹配到的节点
+ result.matchs.clear();
+ }
+
+ if(result != null && result.matchs.size() >0 && pattern.rootNodeType != null){
+ QLMatchResultTree tempTree = new QLMatchResultTree(pattern.rootNodeType,nodes.get(0).createExpressNode(pattern.rootNodeType,null));
+ tempTree.addLeftAll(result.matchs);
+ result.matchs.clear();
+ result.matchs.add(tempTree);
+ }
+ return result;
+ }
+ private static QLMatchResult matchDetailOneTime(INodeTypeManager aManager,QLPatternNode pattern ,List extends IDataNode> nodes,int point,AtomicLong maxMatchPoint) throws Exception{
+ QLMatchResult result = null;
+ if(pattern.nodeType == aManager.findNodeType("EOF") && point == nodes.size()){
+ result = new QLMatchResult(new ArrayList(), point + 1);
+ }else if(pattern.nodeType == aManager.findNodeType("EOF") && point < nodes.size() && nodes.get(point).getValue().equals("}") ){
+ result = new QLMatchResult(new ArrayList(), point);
+ }else if(point == nodes.size() && pattern.nodeType.getPatternNode() != null){
+ result = findMatchStatementWithAddRoot(aManager,pattern.nodeType.getPatternNode(),nodes,point,false,maxMatchPoint);
+ }else if( point < nodes.size()){
+ INodeType tempNodeType = nodes.get(point).getTreeType();
+
+ if(tempNodeType == null){
+ tempNodeType = nodes.get(point).getNodeType();
+ }
+ if(tempNodeType != null && tempNodeType.equals(pattern.nodeType)==false){
+ tempNodeType = null;
+ }
+
+ if(tempNodeType != null){
+ List tempList = new ArrayList();
+ tempList.add(new QLMatchResultTree(tempNodeType,nodes.get(point),pattern.targetNodeType));
+ point = point + 1;
+ result = new QLMatchResult(tempList, point);
+ traceLog(pattern,result,nodes,point - 1,1);
+ }else if(pattern.nodeType.getPatternNode() != null){
+ result = findMatchStatementWithAddRoot(aManager,pattern.nodeType.getPatternNode(),nodes,point,false,maxMatchPoint);
+ if(pattern.targetNodeType != null && result != null && result.matchs.size() >0){
+ if(result.matchs.size() > 1){
+ throw new Exception("设置了类型转换的语法,只能有一个根节点");
+ }
+ result.matchs.get(0).targetNodeType = pattern.targetNodeType;
+ }
+ }
+ if(pattern.blame == true){//取返处理
+ if( result == null){
+ List tempList = new ArrayList();
+ tempList.add(new QLMatchResultTree(tempNodeType,nodes.get(point),null));
+ point = point + 1;
+ result = new QLMatchResult(tempList, point);
+ }else{
+ result = null;
+ }
+ }
+ }
+ if(result != null && result.matchLastIndex > maxMatchPoint.longValue()){
+ maxMatchPoint.set(result.matchLastIndex);
+ }
+ return result;
+
+ }
+
+ private static QLMatchResult matchOrOneTime(INodeTypeManager aManager,
+ QLPatternNode pattern, List extends IDataNode> nodes, int point,
+ AtomicLong maxMatchPoint) throws Exception {
+ QLMatchResult result = null;
+ for (QLPatternNode item : pattern.children) {
+ QLMatchResult tempResult = findMatchStatementWithAddRoot(aManager,item, nodes, point, false, maxMatchPoint);
+ if (tempResult != null) {
+ return tempResult;
+ }
+ }
+ return result;
+ }
+ private static QLMatchResult matchAndOneTime(INodeTypeManager aManager,QLPatternNode pattern ,List extends IDataNode> nodes,int point,AtomicLong maxMatchPoint) throws Exception{
+ int orgiPoint = point;
+ QLMatchResultTree root = null;
+ int matchCount =0;//用于调试日志的输出
+ List tempList =null;
+ for (QLPatternNode item : pattern.children) {
+ if(point > nodes.size()){
+ return null;
+ }
+ QLMatchResult tempResult = findMatchStatementWithAddRoot(aManager,item,nodes,
+ point,false,maxMatchPoint);
+ if (tempResult != null) {
+ if(tempResult.matchs.size() > 0){
+ matchCount = matchCount + 1;
+ }
+ if(tempList == null){
+ tempList = new ArrayList();
+ }
+ point = tempResult.matchLastIndex;
+ if (item.isTreeRoot == true && tempResult.matchs.size() >0) {
+ if (tempResult.matchs.size() > 1)
+ throw new Exception("根节点的数量必须是1");
+ if (root == null) {
+ QLMatchResultTree tempTree = tempResult.matchs.get(0);
+ while(tempTree.getLeft()!= null && tempTree.getLeft().size()>0){
+ tempTree = tempTree.getLeft().get(0);
+ }
+ tempTree.addLeftAll(tempList);
+ tempList.clear();
+ } else {
+ tempResult.matchs.get(0).addLeft(root);
+ }
+ root = tempResult.matchs.get(0);
+ } else if (root != null) {
+ root.addRightAll(tempResult.matchs);
+ } else {
+ tempList.addAll(tempResult.matchs);
+ }
+ }else{
+ return null;
+ }
+ }
+ if(root != null){
+ tempList.add(root);
+ }
+ QLMatchResult result = new QLMatchResult(tempList,point);
+ traceLog(pattern,result,nodes,orgiPoint,matchCount);
+ return result;
+ }
+
+ public static void traceLog(QLPatternNode pattern, QLMatchResult result,
+ List extends IDataNode> nodes, int point,int matchCount) {
+ if (log.isTraceEnabled() && (pattern.matchMode ==MatchMode.DETAIL || pattern.matchMode == MatchMode.AND && matchCount > 1 && pattern.name.equals("ANONY_PATTERN") == false )) {
+ log.trace("匹配--" + pattern.name +"[" + point + ":" + (result.matchLastIndex -1)+ "]:" + pattern);
+ }
+ }
+}
+
+
diff --git a/src/main/java/com/ql/util/express/match/QLPatternNode.java b/src/main/java/com/ql/util/express/match/QLPatternNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..c50a5e92cfab73a51fe0f232149ff28599a71ee5
--- /dev/null
+++ b/src/main/java/com/ql/util/express/match/QLPatternNode.java
@@ -0,0 +1,272 @@
+package com.ql.util.express.match;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+enum MatchMode{
+ AND,OR,DETAIL,NULL
+}
+public class QLPatternNode{
+ private static final Log log = LogFactory.getLog(QLPatternNode.class);
+ INodeTypeManager nodeTypeManager;
+
+ String name;
+
+ /**
+ * 原始的字符串
+ */
+ String orgiContent;
+ /**
+ * 匹配模式
+ */
+ MatchMode matchMode =MatchMode.NULL ;
+ /**
+ * 是否一个子匹配模式
+ */
+ boolean isChildMode = false;
+ /**
+ * 层次
+ */
+ int level =0;
+ /**
+ * 是否根节点,例如:if^
+ */
+ protected boolean isTreeRoot;
+
+ /**
+ * 最小匹配次数,0..n
+ */
+ protected int minMatchNum =1;
+
+ /**
+ * 最大匹配次数
+ */
+ protected int maxMatchNum =1;
+
+
+ /**
+ * 匹配类型,例如 ID,if,SELECT
+ */
+ protected INodeType nodeType;
+
+ /**
+ * 匹配到的节点需要转换成的类型,例如 ID->CONST_STRING
+ */
+ protected INodeType targetNodeType;
+
+ /**
+ * 需要转为的虚拟类型,例如:(ID$(,$ID)*)#COL_LIST
+ */
+ protected INodeType rootNodeType;
+
+ /**
+ * 是否匹配成功,但在输出的时候忽略,用"~"表示
+ * CONST$(,~$CONST)*
+ */
+ protected boolean isSkip;
+
+ /**
+ * 取反,例如:+@,匹配不是+的所有字符
+ */
+ protected boolean blame = false;
+
+
+ /**
+ * 子匹配模式
+ */
+ List children = new ArrayList();
+
+ protected QLPatternNode(INodeTypeManager aManager,String aName,String aOrgiContent) throws Exception{
+ this(aManager,aName,aOrgiContent,false,1);
+ if(this.toString().equals(aOrgiContent)==false){
+ throw new Exception("语法定义解析后的结果与原始值不一致,原始值:"+ aOrgiContent + " 解析结果:" + this.toString());
+ }
+ }
+ protected QLPatternNode(INodeTypeManager aManager,String aName,String aOrgiContent,boolean aIsChildMode,int aLevel) throws Exception{
+ this.nodeTypeManager = aManager;
+ this.name = aName;
+ this.orgiContent = aOrgiContent;
+ this.isChildMode = aIsChildMode;
+ this.level = aLevel;
+ this.splitChild();
+ }
+ public void splitChild() throws Exception{
+ if(log.isTraceEnabled()){
+ String str ="";
+ for(int i=0;i 0){
+ tempStr = tempStr + orgStr.charAt(i);
+ }else if(orgStr.charAt(i) == '$'){
+ if (this.matchMode != MatchMode.NULL
+ && this.matchMode != MatchMode.AND) {
+ throw new Exception("不正确的模式串,在一个匹配模式中不能|,$并存,请使用字串模式:"
+ + orgStr);
+ }
+ children.add(new QLPatternNode(this.nodeTypeManager,"ANONY_PATTERN",tempStr, false,this.level + 1));
+ this.matchMode = MatchMode.AND;
+ tempStr = "";
+ }else if(orgStr.charAt(i) == '|'){
+ if (this.matchMode != MatchMode.NULL
+ && this.matchMode != MatchMode.OR) {
+ throw new Exception("不正确的模式串,在一个匹配模式中不能|,$并存,请使用字串模式:"
+ + orgStr);
+ }
+ children.add(new QLPatternNode(this.nodeTypeManager,"ANONY_PATTERN",tempStr, false,this.level + 1));
+ this.matchMode = MatchMode.OR;
+ tempStr = "";
+ }else if(orgStr.charAt(i) == '#'){
+ this.rootNodeType = this.nodeTypeManager.findNodeType(orgStr.substring(i+1));
+ break;
+ }else {
+ tempStr = tempStr + orgStr.charAt(i);
+ }
+ }
+ // 处理没有()的内容
+ if (count > 0) {
+ throw new Exception("不正确的模式串,(没有找到对应的):" + orgStr);
+ }
+
+ if(this.children.size() > 0){
+ children.add(new QLPatternNode(this.nodeTypeManager,"ANONY_PATTERN",tempStr, false,this.level + 1));
+ tempStr ="";
+ }
+
+ //需要剔除乘法*的情况
+ if(tempStr.endsWith("*") && tempStr.length() >1){
+ this.minMatchNum = 0;
+ this.maxMatchNum = Integer.MAX_VALUE;
+ tempStr = tempStr.substring(0,tempStr.length() -1);
+ }
+
+ if(tempStr.endsWith("}")){
+ int index = tempStr.lastIndexOf("{");
+ if(index > 0){
+ String numStr = tempStr.substring(index + 1,tempStr.length() - 1);
+ int index2 = numStr.indexOf(':');
+ if (index2 > 0) {
+ this.minMatchNum = Integer.parseInt(numStr.substring(0, index2));
+ this.maxMatchNum = Integer.parseInt(numStr.substring(index2 + 1));
+ } else {
+ this.minMatchNum = Integer.parseInt(numStr);
+ this.maxMatchNum = Integer.parseInt(numStr);
+ }
+ tempStr = tempStr.substring(0,index);
+ }
+ }
+ if(tempStr.endsWith("^")==true && tempStr.length() > 1){
+ this.isTreeRoot = true;
+ tempStr = tempStr.substring(0,tempStr.length() -1);
+ }
+
+
+ if(tempStr.endsWith("~") && tempStr.length() >1){
+ this.isSkip = true;
+ tempStr = tempStr.substring(0,tempStr.length() -1);
+ }
+ if(tempStr.endsWith("@") && tempStr.length() >1){
+ this.blame = true;
+ tempStr = tempStr.substring(0,tempStr.length() -1);
+ }
+
+ //处理(ABC|bcd)模式
+ if(tempStr.length() > 2 && tempStr.charAt(0)=='(' && tempStr.charAt(tempStr.length() - 1) ==')'){
+ this.isChildMode = true;
+ this.children.add(new QLPatternNode(this.nodeTypeManager,"ANONY_PATTERN",tempStr.substring(1, tempStr.length() - 1), false,this.level + 1));
+ this.matchMode = MatchMode.AND;
+ tempStr = "";
+
+ }
+
+ int index = tempStr.indexOf("->");
+ if (index > 0) {
+ this.targetNodeType = this.nodeTypeManager.findNodeType(tempStr.substring(index + 2));
+ tempStr = tempStr.substring(0, index);
+ }
+ if (tempStr.length() > 0) {
+ this.matchMode = MatchMode.DETAIL;
+ this.nodeType = this.nodeTypeManager.findNodeType(tempStr);
+ }
+ }
+ public List getChildren(){
+ return this.children;
+ }
+ public INodeType getNodeType(){
+ return this.nodeType;
+ }
+
+ public boolean isDetailMode(){
+ return this.matchMode == MatchMode.DETAIL;
+ }
+ public boolean isAndMode(){
+ return this.matchMode == MatchMode.AND;
+ }
+ public String toString(){
+ String result ="";
+ if(this.matchMode == MatchMode.AND){
+ result = this.joinStringList(this.children,"$");
+ }else if(this.matchMode ==MatchMode.OR){
+ result = this.joinStringList(this.children,"|");
+ }else{
+ result = this.nodeType.getName();
+ }
+ if(this.targetNodeType != null){
+ result = result +"->" + this.targetNodeType.getName();
+ }
+ if(this.isChildMode == true){
+ result ="("+ result + ")";
+ }
+ if(this.isSkip){
+ result = result +'~';
+ }
+ if(this.blame){
+ result = result +'@';
+ }
+ if(this.isTreeRoot){
+ result = result +'^';
+ }
+ if(this.minMatchNum == 0 && this.maxMatchNum == Integer.MAX_VALUE){
+ result = result +'*';
+ }else if(this.minMatchNum == this.maxMatchNum && this.maxMatchNum > 1) {
+ result = result + "{" + this.maxMatchNum +"}";
+ }else if(this.minMatchNum != this.maxMatchNum){
+ result = result + "{" + this.minMatchNum +":" + this.maxMatchNum +"}";
+ }
+
+ if(this.rootNodeType != null){
+ result = result + '#'+ this.rootNodeType.getName();
+ }
+ return result;
+ }
+ public String joinStringList(List list,String splitChar){
+ StringBuffer buffer = new StringBuffer();
+ for(int i=0;i0){buffer.append(splitChar);}
+ buffer.append(list.get(i));
+ }
+ return buffer.toString();
+ }
+}
+
diff --git a/src/main/java/com/ql/util/express/parse/AppendingClassFieldManager.java b/src/main/java/com/ql/util/express/parse/AppendingClassFieldManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..dd31e00e3910394768a5a97eaa69279496045b48
--- /dev/null
+++ b/src/main/java/com/ql/util/express/parse/AppendingClassFieldManager.java
@@ -0,0 +1,58 @@
+package com.ql.util.express.parse;
+
+import com.ql.util.express.*;
+import com.ql.util.express.instruction.OperateDataCacheManager;
+import com.ql.util.express.instruction.op.OperatorBase;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by tianqiao on 16/10/16.
+ */
+public class AppendingClassFieldManager {
+
+ public class AppendingField {
+ public String name;
+
+ public Class> bindingClass;
+
+ public Operator op;
+
+ public Class> returnType;
+
+ public AppendingField(String name, Class> bindingClass,Class> returnType, Operator op) {
+ this.name = name;
+ this.bindingClass = bindingClass;
+ this.op = op;
+ this.returnType = returnType;
+ }
+ }
+
+ private List Fields = new ArrayList();
+
+ public void addAppendingField(String name,Class> bindingClass,Class> returnType, Operator op)
+ {
+ Fields.add(new AppendingField(name,bindingClass,returnType,op));
+ }
+
+ public AppendingField getAppendingClassField(Object object, String FieldName)
+ {
+ for(AppendingField Field : Fields){
+ //object是定义类型的子类
+ if(FieldName.equals(Field.name) && (object.getClass()==Field.bindingClass || Field.bindingClass.isAssignableFrom(object.getClass()))){
+ return Field;
+ }
+ }
+ return null;
+
+ }
+
+ public Object invoke(AppendingField Field, InstructionSetContext context, Object aFieldObject, List errorList) throws Exception {
+ Operator op = Field.op;
+ Object result = op.executeInner(new Object[]{aFieldObject});
+ return result;
+ }
+
+
+}
diff --git a/src/main/java/com/ql/util/express/parse/AppendingClassMethodManager.java b/src/main/java/com/ql/util/express/parse/AppendingClassMethodManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..dc817b768aced6bbcfa1683b5da4bd7f6ccd36c6
--- /dev/null
+++ b/src/main/java/com/ql/util/express/parse/AppendingClassMethodManager.java
@@ -0,0 +1,55 @@
+package com.ql.util.express.parse;
+
+import com.ql.util.express.ArraySwap;
+import com.ql.util.express.InstructionSetContext;
+import com.ql.util.express.OperateData;
+import com.ql.util.express.instruction.op.OperatorBase;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by tianqiao on 16/10/16.
+ */
+public class AppendingClassMethodManager {
+
+ public class AppendingMethod {
+ public String name;
+
+ public Class> bindingClass;
+
+ public OperatorBase op;
+
+ public AppendingMethod(String name, Class> bindingClass, OperatorBase op) {
+ this.name = name;
+ this.bindingClass = bindingClass;
+ this.op = op;
+ }
+ }
+
+ private List methods = new ArrayList();
+
+ public void addAppendingMethod(String name,Class> bindingClass,OperatorBase op)
+ {
+ methods.add(new AppendingMethod(name,bindingClass,op));
+ }
+
+ public AppendingMethod getAppendingClassMethod(Object object, String methodName)
+ {
+ for(AppendingMethod method : methods){
+ //object是定义类型的子类
+ if(methodName.equals(method.name) && (object.getClass()==method.bindingClass || method.bindingClass.isAssignableFrom(object.getClass()))){
+ return method;
+ }
+ }
+ return null;
+
+ }
+
+ public OperateData invoke(AppendingMethod method, InstructionSetContext context, ArraySwap list, List errorList) throws Exception {
+ OperatorBase op = method.op;
+ return op.execute(context,list,errorList);
+ }
+
+
+}
diff --git a/src/main/java/com/ql/util/express/parse/ExpressNode.java b/src/main/java/com/ql/util/express/parse/ExpressNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..0f6e6e4a442f8dcef80759b6e2e5f1c06786f61e
--- /dev/null
+++ b/src/main/java/com/ql/util/express/parse/ExpressNode.java
@@ -0,0 +1,220 @@
+package com.ql.util.express.parse;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.ql.util.express.match.IDataNode;
+import com.ql.util.express.match.INodeType;
+
+
+public class ExpressNode implements IDataNode{
+ /**
+ * 节点类型
+ */
+ private NodeType nodeType;
+
+ private NodeType treeType;
+ /**
+ * 节点值
+ */
+ private String value;
+
+ /**
+ * 节点原始值
+ */
+ private String orgiValue;
+
+ private Object objectValue;
+ /**
+ * 父节点
+ */
+ private ExpressNode parent;
+ private List leftChildren;
+ private List rightChildren;
+ private boolean isSplitStatement = false;
+
+ /**
+ * 行号
+ */
+ private int line;
+ /**
+ * 列号
+ */
+ private int col;
+
+ public ExpressNode(NodeType aType,String aValue) throws Exception{
+ this(aType, aValue, null,null,null,-1,-1);
+ }
+ public ExpressNode(NodeType aType,String aValue,String aOrgiValue,Object aObjectValue,NodeType aTreeType,int aLine,int aCol) throws Exception{
+ if(aType == null){
+ throw new Exception(aValue + " 没有找到对应的节点类型");
+ }
+ this.nodeType = aType;
+ this.treeType = aTreeType;
+ if(aValue != null && aValue.length() >0){
+ this.value = aValue;
+ }
+ if(aOrgiValue != null && aOrgiValue.length() >0){
+ this.orgiValue = aOrgiValue;
+ }
+ if(aObjectValue != null){
+ this.objectValue = aObjectValue;
+ }
+ this.line = aLine;
+ this.col =aCol;
+ }
+
+ public boolean isTypeEqualsOrChild(String parent){
+ boolean result = this.getTreeType().isEqualsOrChild(parent);
+ if(result == false && this.treeType != null){
+ result = this.getNodeType().isEqualsOrChild(parent);
+ }
+ return result;
+ }
+
+ public NodeType getNodeType() {
+ return nodeType;
+ }
+ public void setNodeType(NodeType type) {
+ this.nodeType = type;
+ }
+ public String getValue() {
+ if(value == null){
+ return this.nodeType.getName();
+ }else{
+ return value;
+ }
+ }
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ public boolean isSplitStatement() {
+ return isSplitStatement;
+ }
+ public void setSplitStatement(boolean isSplitStatement) {
+ this.isSplitStatement = isSplitStatement;
+ }
+
+ public String getInstructionFactory(){
+ if(this.nodeType.getInstructionFactory() != null){
+ return this.nodeType.getInstructionFactory();
+ }
+ if(this.treeType != null && this.treeType.getInstructionFactory() != null){
+ return this.treeType.getInstructionFactory();
+ }
+ throw new RuntimeException("没有定义节点的指令InstructionFactory信息:" + this.nodeType.getName()+ (this.treeType == null?"":" 或者 " +this.treeType.getName()) );
+ }
+
+ public String getOrgiValue() {
+ return orgiValue;
+ }
+ public void setOrgiValue(String orgiValue) {
+ this.orgiValue = orgiValue;
+ }
+ public Object getObjectValue() {
+ return objectValue;
+ }
+ public void setObjectValue(Object objectValue) {
+ this.objectValue = objectValue;
+ }
+ public ExpressNode getParent() {
+ return parent;
+ }
+ public void setParent(ExpressNode parent) {
+ this.parent = parent;
+ }
+
+ public int getLine() {
+ return line;
+ }
+ public void setLine(int line) {
+ this.line = line;
+ }
+
+ public int getCol() {
+ return col;
+ }
+ public void setCol(int col) {
+ this.col = col;
+ }
+ public NodeType getRealTreeType(){
+ return this.treeType;
+ }
+
+ public NodeType getTreeType() {
+ if(this.treeType == null){
+ return this.nodeType;
+ }else{
+ return treeType;
+ }
+ }
+
+ public void setTreeType(NodeType treeType) {
+ this.treeType = treeType;
+ }
+
+ public List getLeftChildren() {
+ return leftChildren;
+ }
+ public void setLeftChildren(List leftChildren) {
+ this.leftChildren = leftChildren;
+ }
+ public List getRightChildren() {
+ return rightChildren;
+ }
+ public void setRightChildren(List rightChildren) {
+ this.rightChildren = rightChildren;
+ }
+ public void addLeftChild(ExpressNode leftChild){
+ if(leftChild == null){
+ return ;
+ }
+ if(this.leftChildren ==null){
+ this.leftChildren = new ArrayList();
+ }
+ this.leftChildren.add(leftChild);
+ }
+
+ public void addRightChild(ExpressNode rightChild){
+ if(rightChild == null){
+ return ;
+ }
+ if(this.leftChildren ==null){
+ this.leftChildren = new ArrayList();
+ }
+ this.leftChildren.add(rightChild);
+ }
+
+ public ExpressNode[] getChildren(){
+ List result = new ArrayList();
+ if(this.leftChildren != null && this.leftChildren.size() >0){
+ result.addAll(this.leftChildren);
+ }
+ if(this.rightChildren != null && this.rightChildren.size() >0){
+ result.addAll(this.rightChildren);
+ }
+ return result.toArray(new ExpressNode[0]);
+ }
+
+ public String toString(){
+ String str = (this.orgiValue == null ? this.getValue():this.orgiValue) + (this.nodeType.getName() == null?"":(":" + this.nodeType.getName()));
+ // return str + "[" + this.line +"," + this.col +"]";
+ return str;
+ }
+ public IDataNode createExpressNode(INodeType aType, String aValue) throws Exception {
+ return new ExpressNode((NodeType)aType,aValue);
+ }
+ public void setNodeType(INodeType type) {
+ this.setNodeType((NodeType)type);
+
+ }
+ @Override
+ public void addLeftChild(IDataNode ref) {
+ this.addLeftChild((ExpressNode)ref);
+ }
+ @Override
+ public void setTreeType(INodeType aTreeType) {
+ this.setTreeType((NodeType)aTreeType);
+ }
+}
diff --git a/src/main/java/com/ql/util/express/parse/ExpressPackage.java b/src/main/java/com/ql/util/express/parse/ExpressPackage.java
new file mode 100644
index 0000000000000000000000000000000000000000..570d01fe1a4b41e2c388c41f285a02c79c08396b
--- /dev/null
+++ b/src/main/java/com/ql/util/express/parse/ExpressPackage.java
@@ -0,0 +1,115 @@
+package com.ql.util.express.parse;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class ExpressPackage {
+ private List m_packages;
+ private Map> name2CallCache = null;
+ private Class> S_NULL = NullClass.class;
+ private ExpressPackage parent;
+ public ExpressPackage(ExpressPackage aParent) {
+ this.parent = aParent;
+ }
+ public void addPackage(String aPackageName) {
+ if(this.m_packages == null){
+ this.m_packages = new ArrayList();
+ }
+ int point = aPackageName.indexOf(".*");
+ if(point >=0){
+ aPackageName = aPackageName.substring(0, point);
+ }
+ this.m_packages.add(aPackageName);
+ }
+
+ public void removePackage(String aPackageName) {
+ if(this.m_packages != null){
+ this.m_packages.remove(aPackageName);
+ }
+ }
+
+ public Class> getClass(String name) {
+ Class> tempClass = null;
+ if (this.parent != null){
+ tempClass = this.parent.getClass(name);
+ }
+ if(tempClass == null){
+ if(this.m_packages == null && this.parent != null){
+ return null;
+ }
+ if (this.name2CallCache == null) {
+ this.name2CallCache = new ConcurrentHashMap>();
+ }else{
+ tempClass = this.name2CallCache.get(name);
+ }
+ if(tempClass == null){
+ tempClass = this.getClassInner(name,this.parent == null);
+ if(tempClass == null){
+ tempClass = S_NULL ;
+ }
+ }
+ this.name2CallCache.put(name, tempClass);
+ }
+
+ if(tempClass == S_NULL){
+ return null;
+ }else{
+ return tempClass;
+ }
+ }
+
+ private Class> getClassInner(String name,boolean isRootCall) {
+ Class> result = null;
+ if (isRootCall == true) {
+ // 如果本身具有包名,这直接定位
+ if (name.indexOf(".") >= 0) {
+ try {
+ result = Class.forName(name);
+ } catch (Throwable ex) {
+ }
+ return result;
+ }
+ if (Integer.TYPE.getName().equals(name) == true)
+ return Integer.TYPE;
+ if (Short.TYPE.getName().equals(name) == true)
+ return Short.TYPE;
+ if (Long.TYPE.getName().equals(name) == true)
+ return Long.TYPE;
+ if (Double.TYPE.getName().equals(name) == true)
+ return Double.TYPE;
+ if (Float.TYPE.getName().equals(name) == true)
+ return Float.TYPE;
+ if (Byte.TYPE.getName().equals(name) == true)
+ return Byte.TYPE;
+ if (Character.TYPE.getName().equals(name) == true)
+ return Character.TYPE;
+ if (Boolean.TYPE.getName().equals(name) == true)
+ return Boolean.TYPE;
+ }
+ if (this.m_packages != null) {
+ for (int i = 0; i < m_packages.size(); i++) {
+ String tmp = "";
+ if (m_packages.get(i).endsWith("." + name) == true) {
+ tmp = m_packages.get(i);
+ } else {
+ tmp = m_packages.get(i) + "." + name;
+ }
+ try {
+ result = Class.forName(tmp);
+ } catch (ClassNotFoundException ex) {
+ // 不做任何操作
+ }
+ if (result != null) {
+ return result;
+ }
+ }
+ }
+ return null;
+ }
+}
+
+class NullClass{
+
+}
diff --git a/src/main/java/com/ql/util/express/parse/ExpressParse.java b/src/main/java/com/ql/util/express/parse/ExpressParse.java
new file mode 100644
index 0000000000000000000000000000000000000000..80c3fab003b4dd1cb0ed541e52aab9dc4a989806
--- /dev/null
+++ b/src/main/java/com/ql/util/express/parse/ExpressParse.java
@@ -0,0 +1,360 @@
+package com.ql.util.express.parse;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import com.ql.util.express.ExpressUtil;
+import com.ql.util.express.IExpressResourceLoader;
+import com.ql.util.express.match.QLMatchResult;
+import com.ql.util.express.match.QLPattern;
+
+public class ExpressParse {
+
+ private static final Log log = LogFactory.getLog(ExpressParse.class);
+ NodeTypeManager nodeTypeManager;
+ IExpressResourceLoader expressResourceLoader;
+ /**
+ * 是否需要高精度计算
+ */
+ private boolean isPrecise = false;
+ public ExpressParse(NodeTypeManager aNodeTypeManager,IExpressResourceLoader aLoader,boolean aIsPrecise){
+ this.nodeTypeManager = aNodeTypeManager;
+ this.expressResourceLoader = aLoader;
+ this.isPrecise = aIsPrecise;
+ }
+ protected Word[] getExpressByName(String expressFileName) throws Exception{
+ String express = this.expressResourceLoader.loadExpress(expressFileName);
+ return WordSplit.parse(nodeTypeManager.splitWord, express);
+ }
+ protected Word[] dealInclude(Word[] wordObjects) throws Exception{
+ boolean isInclude = false;
+ StringBuffer includeFileName = new StringBuffer();
+ int point = 0;
+ List result = new ArrayList();
+ while(point transferWord2ExpressNode(ExpressPackage aRootExpressPackage,Word[] wordObjects,Map selfClassDefine,boolean dealJavaClass) throws Exception{
+ List result = new ArrayList();
+ String tempWord;
+ NodeType tempType;
+ int point = 0;
+ ExpressPackage tmpImportPackage = null;
+ if(dealJavaClass==true){
+ tmpImportPackage = new ExpressPackage(aRootExpressPackage);
+ //先处理import,import必须放在文件的最开始,必须以;结束
+ boolean isImport = false;
+ StringBuffer importName = new StringBuffer();
+ while(point ='0' && firstChar<='9'){
+ if(result.size() >0){//对 负号进行特殊处理
+ if(result.get(result.size() -1).getValue().equals("-")){
+ if(result.size() == 1
+ || result.size() >=2
+ && ( result.get(result.size() - 2).isTypeEqualsOrChild("OP_LIST")
+ || result.get(result.size() - 2).isTypeEqualsOrChild(",")
+ )
+ && result.get(result.size() - 2).isTypeEqualsOrChild(")")==false
+ && result.get(result.size() - 2).isTypeEqualsOrChild("]")==false
+ ){
+ result.remove(result.size() -1);
+ tempWord = "-" + tempWord;
+ }
+ }
+ }
+ if(lastChar =='d'){
+ tempType = nodeTypeManager.findNodeType("CONST_DOUBLE");
+ tempWord = tempWord.substring(0,tempWord.length() -1);
+ if(this.isPrecise == true){
+ objectValue = new BigDecimal(tempWord);
+ }else{
+ objectValue = Double.valueOf(tempWord);
+ }
+ }else if(lastChar =='f'){
+ tempType = nodeTypeManager.findNodeType("CONST_FLOAT");
+ tempWord = tempWord.substring(0,tempWord.length() -1);
+ if(this.isPrecise == true){
+ objectValue = new BigDecimal(tempWord);
+ }else{
+ objectValue = Float.valueOf(tempWord);
+ }
+ }else if(tempWord.indexOf(".") >=0){
+ tempType = nodeTypeManager.findNodeType("CONST_DOUBLE");
+ if(this.isPrecise == true){
+ objectValue = new BigDecimal(tempWord);
+ }else{
+ objectValue = Double.valueOf(tempWord);
+ }
+ }else if(lastChar =='l'){
+ tempType = nodeTypeManager.findNodeType("CONST_LONG");
+ tempWord = tempWord.substring(0,tempWord.length() -1);
+ objectValue = Long.valueOf(tempWord);
+ }else{
+ long tempLong = Long.parseLong(tempWord);
+ if(tempLong <= Integer.MAX_VALUE && tempLong >= Integer.MIN_VALUE){
+ tempType = nodeTypeManager.findNodeType("CONST_INTEGER");
+ objectValue = Integer.valueOf((int)tempLong);
+ }else{
+ tempType = nodeTypeManager.findNodeType("CONST_LONG");
+ objectValue = Long.valueOf(tempLong);
+ }
+ }
+ treeNodeType = nodeTypeManager.findNodeType("CONST");
+ point = point + 1;
+ }else if(firstChar =='"'){
+ if(lastChar !='"' || tempWord.length() <2){
+ throw new Exception("没有关闭的字符串:" + tempWord);
+ }
+ tempWord = tempWord.substring(1,tempWord.length() -1);
+ tempType =nodeTypeManager.findNodeType("CONST_STRING");
+ objectValue = tempWord;
+ treeNodeType = nodeTypeManager.findNodeType("CONST");
+ point = point + 1;
+ }else if(firstChar =='\''){
+ if(lastChar !='\'' || tempWord.length() <2){
+ throw new Exception("没有关闭的字符:" + tempWord);
+ }
+ tempWord = tempWord.substring(1,tempWord.length() -1);
+
+ treeNodeType = nodeTypeManager.findNodeType("CONST");
+ if(tempWord.length() == 1){ //转换为字符串
+ tempType =nodeTypeManager.findNodeType("CONST_CHAR");
+ objectValue = tempWord.charAt(0);
+ }else{
+ tempType =nodeTypeManager.findNodeType("CONST_STRING");
+ objectValue = tempWord;
+ }
+
+ point = point + 1;
+ }else if(tempWord.equals("true") || tempWord.equals("false")){
+ tempType = nodeTypeManager.findNodeType("CONST_BOOLEAN");
+ treeNodeType = nodeTypeManager.findNodeType("CONST");
+ objectValue = Boolean.valueOf(tempWord);
+ point = point + 1;
+ }else {
+ tempType = nodeTypeManager.isExistNodeTypeDefine(tempWord);
+ if(tempType != null && tempType.getKind() != NodeTypeKind.KEYWORD){
+ //不是关键字
+ tempType = null;
+ }
+ if (tempType == null) {
+ boolean isClass = false;
+ String tmpStr = "";
+ Class> tmpClass = null;
+ if (dealJavaClass == true) {
+ int j = point;
+ while (j < wordObjects.length) {
+ tmpStr = tmpStr + wordObjects[j].word;
+ tmpClass = tmpImportPackage.getClass(tmpStr);
+ if (tmpClass != null) {
+ point = j + 1;
+ isClass = true;
+ break;
+ }
+ if (j < wordObjects.length - 1
+ && wordObjects[j + 1].word.equals(".") == true) {
+ tmpStr = tmpStr + wordObjects[j + 1].word;
+ j = j + 2;
+ continue;
+ } else {
+ break;
+ }
+ }
+ }
+ if (isClass == true){
+ tempWord = ExpressUtil.getClassName(tmpClass);
+ orgiValue = tmpStr;
+ tempType = nodeTypeManager.findNodeType("CONST_CLASS");
+ objectValue = tmpClass;
+ }else if(this.nodeTypeManager.isFunction(tempWord)){
+ tempType = nodeTypeManager.findNodeType("FUNCTION_NAME");
+ point = point + 1;
+ }else if(selfClassDefine != null && selfClassDefine.containsKey(tempWord)){
+ tempType = nodeTypeManager.findNodeType("VClass");
+ point = point + 1;
+ }else{
+ tempType = nodeTypeManager.findNodeType("ID");
+ point = point + 1;
+ }
+ }else{
+ point = point + 1;
+ }
+ }
+ result.add(new ExpressNode(tempType,tempWord,orgiValue,objectValue,treeNodeType,tmpWordObject.line,tmpWordObject.col));
+ treeNodeType = null;
+ objectValue = null;
+ orgiValue = null;
+ }
+ return result;
+ }
+
+ public static void printTreeNode(StringBuilder builder,ExpressNode node, int level){
+ builder.append(level+":" );
+
+ for (int i = 0; i < level; i++) {
+ builder.append(" ");
+ }
+ builder.append(node);
+ if(builder.length() <100){
+ for (int i = 0; i <100 - builder.length(); i++) {
+ builder.append(" ");
+ }
+ }
+ builder.append("\t"+ node.getTreeType().getName()).append("\n");
+
+ List leftChildren = node.getLeftChildren();
+ if (leftChildren != null && leftChildren.size() > 0) {
+ for (ExpressNode item : leftChildren) {
+ printTreeNode(builder,item, level + 1);
+ }
+ }
+ List rightChildren = node.getRightChildren();
+ if (rightChildren != null && rightChildren.size() > 0) {
+ for (ExpressNode item : rightChildren) {
+ printTreeNode(builder,item, level + 1);
+ }
+ }
+ }
+ public static void printTreeNode(ExpressNode node, int level) {
+ StringBuilder builder = new StringBuilder();
+ printTreeNode(builder,node,level);
+ System.out.println(builder.toString());
+ }
+
+ public static void resetParent(ExpressNode node,ExpressNode parent){
+ node.setParent(parent);
+ List leftChildren = node.getLeftChildren();
+ if (leftChildren != null && leftChildren.size() > 0) {
+ for (ExpressNode item : leftChildren) {
+ resetParent(item,node);
+ }
+ }
+ List rightChildren = node.getRightChildren();
+ if (rightChildren != null && rightChildren.size() > 0) {
+ for (ExpressNode item : rightChildren) {
+ resetParent(item,node);
+ }
+ }
+ }
+ /**
+ * 提取自定义的Class
+ * @param words
+ * @return
+ */
+ public static void fetchSelfDefineClass(Word[] words,Map selfDefineClass){
+ for(int i=0;i selfDefineClass) throws Exception{
+ Word[] words = WordSplit.parse(this.nodeTypeManager.splitWord,express);
+ if(isTrace == true && log.isDebugEnabled()){
+ log.debug("执行的表达式:" + express);
+ log.debug("单词分解结果:" + WordSplit.getPrintInfo(words,","));
+ }
+ words = this.dealInclude(words);
+ if(isTrace == true && log.isDebugEnabled()){
+ log.debug("预处理后结果:" + WordSplit.getPrintInfo(words,","));
+ }
+
+ //提取自定义Class
+ if(selfDefineClass == null){
+ selfDefineClass = new HashMap();
+ }
+ fetchSelfDefineClass(words,selfDefineClass);
+
+ List tempList = this.transferWord2ExpressNode(rootExpressPackage,words,selfDefineClass,true);
+ if(isTrace == true && log.isDebugEnabled()){
+ log.debug("单词分析结果:" + printInfo(tempList,","));
+ }
+
+
+ QLMatchResult result = QLPattern.findMatchStatement(this.nodeTypeManager, this.nodeTypeManager
+ .findNodeType("PROGRAM").getPatternNode(), tempList,0);
+ if(result == null){
+ throw new Exception("语法匹配失败");
+ }
+ if(result.getMatchLastIndex() < tempList.size()){
+ int maxPoint = result.getMatchLastIndex();
+ ExpressNode tempNode = tempList.get(maxPoint);
+ throw new Exception("还有单词没有完成语法匹配:" + result.getMatchLastIndex() +"["+ tempNode.getValue() + ":line=" + tempNode.getLine() + ",col=" + tempNode.getCol() +"] 之后的单词 \n" + express);
+ }
+ result.getMatchs().get(0).buildExpressNodeTree();
+ ExpressNode root =(ExpressNode)result.getMatchs().get(0).getRef();
+
+ //为了生成代码时候进行判断,需要设置每个节点的父亲
+ resetParent(root,null);
+
+ if(isTrace == true && log.isDebugEnabled()){
+ log.debug("最后的语法树:" );
+ printTreeNode(root,1);
+ }
+ return root;
+ }
+
+ public static String printInfo(List list,String splitOp){
+ StringBuffer buffer = new StringBuffer();
+ for(int i=0;i 0){buffer.append(splitOp);}
+ buffer.append(list.get(i));
+ }
+ return buffer.toString();
+ }
+}
+
diff --git a/src/main/java/com/ql/util/express/parse/KeyWordDefine4Java.java b/src/main/java/com/ql/util/express/parse/KeyWordDefine4Java.java
new file mode 100644
index 0000000000000000000000000000000000000000..0915af3b109653ce9ce6c4a95dbdd1962728f6b0
--- /dev/null
+++ b/src/main/java/com/ql/util/express/parse/KeyWordDefine4Java.java
@@ -0,0 +1,157 @@
+package com.ql.util.express.parse;
+
+
+public class KeyWordDefine4Java {
+ public String[] splitWord={
+ "~","&","|","<<", ">>",//位操作
+ "+", "-","*", "/", "%","++", "--",//四则运算:
+ ".",",",":",";","(", ")", "{", "}", "[", "]","?",//分隔符号
+ "!","<", ">", "<=", ">=", "==","!=","&&","||",//Boolean运算符号
+ "=","/**","**/"
+ };
+ public String[] keyWords = new String[] {
+ "mod","nor","in",
+ "for", "if","when", "then", "else", "exportAlias", "alias",
+ "break", "continue", "return", "macro", "function" ,
+ "def","exportDef", "new","array","anonymousNewArray",
+ "like","class","VClass",
+ "cast"
+ };
+ public String[] nodeTypeDefines = new String[] {
+ "ID:TYPE=WORDDEF",
+ "EOF:TYPE=WORDDEF",
+ "FUNCTION_NAME:TYPE=WORDDEF",
+ "FUNCTION_DEFINE:TYPE=WORDDEF",
+ "LEFT_BRACKET:TYPE=WORDDEF,DEFINE=(",
+ "RIGHT_BRACKET:TYPE=WORDDEF,DEFINE=)",
+
+ "MAYBE:TYPE=WORDDEF,DEFINE=|",
+ "OR:TYPE=WORDDEF,DEFINE=||",
+ "LEFT_COMMENT:TYPE=WORDDEF,DEFINE=/**",
+ "RIGHT_COMMENT:TYPE=WORDDEF,DEFINE=**/",
+ "MULTI:TYPE=WORDDEF,DEFINE=*",
+
+
+ "CONST_BYTE:TYPE=WORDDEF",
+ "CONST_SHORT:TYPE=WORDDEF",
+ "CONST_INTEGER:TYPE=WORDDEF",
+ "CONST_LONG:TYPE=WORDDEF",
+ "CONST_FLOAT:TYPE=WORDDEF",
+ "CONST_DOUBLE:TYPE=WORDDEF",
+ "CONST_NUMBER:TYPE=WORDDEF,DEFINE=CONST_BYTE|CONST_SHORT|CONST_INTEGER|CONST_LONG|CONST_FLOAT|CONST_DOUBLE",
+ "CONST_CHAR:TYPE=WORDDEF",
+ "CONST_STRING:TYPE=WORDDEF",
+ "CONST_BOOLEAN:TYPE=WORDDEF",
+ "CONST_CLASS:TYPE=WORDDEF",
+ "CONST:TYPE=WORDDEF,DEFINE=CONST_NUMBER|CONST_CHAR|CONST_STRING|CONST_BOOLEAN|CONST_CLASS",
+
+ "CHILD_EXPRESS:TYPE=EXPRESS,DEFINE=LEFT_BRACKET->CHILD_EXPRESS^$(RIGHT_BRACKET~|(EXPRESS$(,~$EXPRESS)*$RIGHT_BRACKET~))",
+ "[]:TYPE=EXPRESS,DEFINE=[~$EXPRESS*$]~#[]",
+
+ "OP_LEVEL1:TYPE=OPERATOR,DEFINE=~|!",
+ "OP_LEVEL2:TYPE=OPERATOR,DEFINE=++|--",
+ "OP_LEVEL3:TYPE=OPERATOR,DEFINE=&|MAYBE|<<|>>",
+ "OP_LEVEL4:TYPE=OPERATOR,DEFINE=*|/|mod|%",
+ "OP_LEVEL5:TYPE=OPERATOR,DEFINE=+|-",
+ "OP_LEVEL6:TYPE=OPERATOR,DEFINE=in|like",
+ "OP_LEVEL7:TYPE=OPERATOR,DEFINE=>|>=|<|<=|==|!=",
+ "OP_LEVEL8:TYPE=OPERATOR,DEFINE=&&",
+ "OP_LEVEL9:TYPE=OPERATOR,DEFINE=OR|nor",
+
+ "OP_LIST:TYPE=GROUP,DEFINE=OP_LEVEL1|OP_LEVEL2|OP_LEVEL3|OP_LEVEL4|OP_LEVEL5|OP_LEVEL6|OP_LEVEL7|OP_LEVEL8|OP_LEVEL9|=|LEFT_BRACKET|RIGHT_BRACKET|[|]|{|}",
+
+ "PARAMETER_LIST:TYPE=STATEMENT,DEFINE=LEFT_BRACKET~$(RIGHT_BRACKET~|(EXPRESS$(,~$EXPRESS)*$RIGHT_BRACKET~))",
+
+
+ "VAR_DEFINE:TYPE=EXPRESS,DEFINE=(CONST_CLASS|VClass->CONST_STRING)$(([$])#[])*$ID->CONST_STRING#def",
+ "EXPORT_VAR_DEFINE:TYPE=EXPRESS,DEFINE=exportDef^$CONST_CLASS$ID->CONST_STRING",
+ "NEW_OBJECT:TYPE=EXPRESS,DEFINE=new->NEW_OBJECT^$CONST_CLASS$PARAMETER_LIST",
+ "NEW_ARRAY:TYPE=EXPRESS,DEFINE=new->NEW_ARRAY^$CONST_CLASS$([]*)",
+ "ANONY_NEW_ARRAY:TYPE=EXPRESS,DEFINE=[->anonymousNewArray^$(]~|(EXPRESS$(,~$EXPRESS)*$]~))",
+
+ "NEW_VIR_OBJECT:TYPE=EXPRESS,DEFINE=new->NEW_VIR_OBJECT^$VClass->CONST_STRING$PARAMETER_LIST",
+
+ "OPDATA:TYPE=EXPRESS,DEFINE=ANONY_NEW_ARRAY|VAR_DEFINE|EXPORT_VAR_DEFINE|NEW_OBJECT|NEW_ARRAY|NEW_VIR_OBJECT|CHILD_EXPRESS|CONST|ID",
+
+ "FIELD_CALL:TYPE=EXPRESS,DEFINE= .->FIELD_CALL^$(ID->CONST_STRING|class->CONST_STRING)",
+ "METHOD_CALL:TYPE=EXPRESS,DEFINE=.->METHOD_CALL^$(ID->CONST_STRING|FUNCTION_NAME->CONST_STRING)$PARAMETER_LIST",
+ "OBJECT_CALL:TYPE=EXPRESS,DEFINE=((COMMENT~)*$OPDATA$(COMMENT~)*)$(METHOD_CALL|FIELD_CALL)^*",
+
+ "FUNCTION_CALL:TYPE=EXPRESS,DEFINE=(ID->CONST_STRING|FUNCTION_NAME->CONST_STRING)$PARAMETER_LIST#FUNCTION_CALL",
+
+ "ARRAY_CALL:TYPE=EXPRESS,DEFINE=(FUNCTION_CALL|OBJECT_CALL)$([->ARRAY_CALL^$EXPRESS$]~)^*$(METHOD_CALL|FIELD_CALL)^*",
+
+
+ "CAST_CALL:TYPE=EXPRESS,DEFINE=(LEFT_BRACKET~$CONST_CLASS$RIGHT_BRACKET~#cast)^*$ARRAY_CALL",
+ "EXPRESS_OP_L1:TYPE=EXPRESS,DEFINE=OP_LEVEL1^*$CAST_CALL",
+ "EXPRESS_OP_L2:TYPE=EXPRESS,DEFINE=EXPRESS_OP_L1$OP_LEVEL2^*",
+ "EXPRESS_OP_L3:TYPE=EXPRESS,DEFINE=EXPRESS_OP_L2$(OP_LEVEL3^$EXPRESS_OP_L2)^*",
+ "EXPRESS_OP_L4:TYPE=EXPRESS,DEFINE=EXPRESS_OP_L3$(OP_LEVEL4^$EXPRESS_OP_L3)^*",
+ "EXPRESS_OP_L5:TYPE=EXPRESS,DEFINE=EXPRESS_OP_L4$(OP_LEVEL5^$EXPRESS_OP_L4)^*",
+ "EXPRESS_OP_L6:TYPE=EXPRESS,DEFINE=EXPRESS_OP_L5$(OP_LEVEL6^$EXPRESS_OP_L5)^*",
+ "EXPRESS_OP_L7:TYPE=EXPRESS,DEFINE=EXPRESS_OP_L6$(OP_LEVEL7^$EXPRESS_OP_L6)^*",
+ "EXPRESS_OP_L8:TYPE=EXPRESS,DEFINE=EXPRESS_OP_L7$(OP_LEVEL8^$EXPRESS_OP_L7)^*",
+ "EXPRESS_OP_L9:TYPE=EXPRESS,DEFINE=EXPRESS_OP_L8$(OP_LEVEL9^$EXPRESS_OP_L8)^*",
+ "EXPRESS_COMPUTER:TYPE=EXPRESS,DEFINE=EXPRESS_OP_L9",
+
+ "EXPRESS_JUDGEANDSET:TYPE=EXPRESS,DEFINE=EXPRESS_COMPUTER$(?->EXPRESS_JUDGEANDSET^$EXPRESS_COMPUTER$:~$EXPRESS_COMPUTER)^{0:1}",
+ "EXPRESS_KEY_VALUE:TYPE=EXPRESS,DEFINE=EXPRESS_JUDGEANDSET$(:->EXPRESS_KEY_VALUE^$(EXPRESS_JUDGEANDSET|STAT_BLOCK))^{0:1}",
+ "EXPRESS_ASSIGN:TYPE=EXPRESS,DEFINE=EXPRESS_KEY_VALUE$(=^$EXPRESS_KEY_VALUE)^*",
+
+ "EXPRESS_RETURN:TYPE=EXPRESS,DEFINE=return^$EXPRESS_ASSIGN",
+ "BREAK_CALL:TYPE=EXPRESS,DEFINE=break^",
+ "CONTINUE_CALL:TYPE=EXPRESS,DEFINE=continue^",
+ "ALIAS_CALL:TYPE=EXPRESS,DEFINE=alias^$ID->CONST_STRING$EXPRESS_ASSIGN",
+ "EXPORT_ALIAS_CALL:TYPE=EXPRESS,DEFINE=exportAlias^$ID->CONST_STRING$EXPRESS_ASSIGN",
+
+ "OP_CALL:TYPE=EXPRESS,DEFINE=(ID->CONST_STRING|FUNCTION_NAME->CONST_STRING)$(EXPRESS$(,~$EXPRESS)*)#FUNCTION_CALL",
+
+ "EXPRESS:TYPE=EXPRESS,DEFINE=BREAK_CALL|CONTINUE_CALL|EXPRESS_RETURN|ALIAS_CALL|EXPORT_ALIAS_CALL|EXPRESS_ASSIGN|OP_CALL",
+
+ "STAT_SEMICOLON:TYPE=STATEMENT,DEFINE=;~|(EXPRESS$(EOF|;)~#STAT_SEMICOLON)",
+
+ "STAT_IFELSE:TYPE=STATEMENT,DEFINE=(if|when->if)^$EXPRESS$then$(STAT_BLOCK|STATEMENT|EXPRESS)$else$(STAT_BLOCK|STATEMENT)",
+ "STAT_IF:TYPE=STATEMENT, DEFINE=(if|when->if)^$EXPRESS$then$(STAT_BLOCK|STATEMENT)",
+ "STAT_IFELSE_JAVA:TYPE=STATEMENT,DEFINE=(if|when->if)^$CHILD_EXPRESS$(STAT_BLOCK|STATEMENT|EXPRESS)$else$(STAT_BLOCK|STATEMENT)",
+ "STAT_IF_JAVA:TYPE=STATEMENT, DEFINE=(if|when->if)^$CHILD_EXPRESS$(STAT_BLOCK|STATEMENT)",
+
+ "PARAMETER_DEFINE:TYPE=STATEMENT,DEFINE=LEFT_BRACKET->CHILD_EXPRESS^$(RIGHT_BRACKET~|(VAR_DEFINE$(,~$VAR_DEFINE)*$RIGHT_BRACKET~))",
+
+ "STAT_FOR:TYPE=STATEMENT,DEFINE=for^$(LEFT_BRACKET~$STATEMENT{0:2}$EXPRESS$RIGHT_BRACKET~#CHILD_EXPRESS)$STAT_BLOCK$;~*",
+ "STAT_MACRO:TYPE=STATEMENT,DEFINE=macro^$ID->CONST_STRING$STAT_BLOCK$;~*",
+ "STAT_FUNCTION:TYPE=STATEMENT,DEFINE=function^$ID->CONST_STRING$PARAMETER_DEFINE$STAT_BLOCK$;~*",
+ "STAT_CLASS:TYPE=STATEMENT,DEFINE=class^$VClass->CONST_STRING$PARAMETER_DEFINE$STAT_BLOCK$;~*",
+
+ "COMMENT:TYPE=BLOCK,DEFINE=LEFT_COMMENT$(RIGHT_COMMENT@)*$RIGHT_COMMENT#COMMENT",
+
+ "STATEMENT:TYPE=STATEMENT,DEFINE=COMMENT|STAT_IFELSE|STAT_IF|STAT_IFELSE_JAVA|STAT_IF_JAVA|STAT_FOR|STAT_MACRO|STAT_FUNCTION|STAT_CLASS|STAT_SEMICOLON",
+
+ "STAT_BLOCK:TYPE=BLOCK,DEFINE={->STAT_BLOCK^$STAT_LIST$}~",
+ "STAT_LIST:TYPE=BLOCK,DEFINE=(STAT_BLOCK|STATEMENT)*",
+ "PROGRAM:TYPE=BLOCK,DEFINE=STAT_LIST#STAT_BLOCK",
+ };
+ public String[][] instructionFacotryMapping = {
+ {"~,!,++,--,&,|,<<,>>,*,/,mod,%,+,-,like,>,>=,<,<=,==,!=,&&,||,nor,=,return,alias,exportAlias,ARRAY_CALL","com.ql.util.express.instruction.OperatorInstructionFactory"},
+ {"in","com.ql.util.express.instruction.InInstructionFactory"},
+ {"exportDef","com.ql.util.express.instruction.OperatorInstructionFactory"},
+ {"ID","com.ql.util.express.instruction.LoadAttrInstructionFactory"},
+ {"CONST,CONST_CLASS","com.ql.util.express.instruction.ConstDataInstructionFactory"},
+ {"[],STAT_SEMICOLON,STAT_BLOCK,FUNCTION_DEFINE,CHILD_EXPRESS","com.ql.util.express.instruction.BlockInstructionFactory"},
+ {"def","com.ql.util.express.instruction.DefineInstructionFactory"},
+ {"NEW_OBJECT,NEW_ARRAY,anonymousNewArray","com.ql.util.express.instruction.NewInstructionFactory"},
+ {"FIELD_CALL","com.ql.util.express.instruction.FieldCallInstructionFactory"},
+ {"METHOD_CALL","com.ql.util.express.instruction.MethodCallInstructionFactory"},
+ {"cast","com.ql.util.express.instruction.CastInstructionFactory"},
+ {"break","com.ql.util.express.instruction.BreakInstructionFactory"},
+ {"continue","com.ql.util.express.instruction.ContinueInstructionFactory"},
+ {"FUNCTION_CALL","com.ql.util.express.instruction.CallFunctionInstructionFactory"},
+ {"if,EXPRESS_JUDGEANDSET","com.ql.util.express.instruction.IfInstructionFactory"},
+ {"for","com.ql.util.express.instruction.ForInstructionFactory"},
+ {"function,class","com.ql.util.express.instruction.FunctionInstructionFactory"},
+ {"macro","com.ql.util.express.instruction.MacroInstructionFactory"},
+ {"NEW_VIR_OBJECT","com.ql.util.express.instruction.NewVClassInstructionFactory"},
+ {"COMMENT","com.ql.util.express.instruction.NullInstructionFactory"},
+ {"EXPRESS_KEY_VALUE","com.ql.util.express.instruction.KeyValueInstructionFactory"},
+
+ };
+}
diff --git a/src/main/java/com/ql/util/express/parse/KeyWordDefine4SQL.java b/src/main/java/com/ql/util/express/parse/KeyWordDefine4SQL.java
new file mode 100644
index 0000000000000000000000000000000000000000..1c5937f4453055a13da06f6c803ffbd3f5a9825f
--- /dev/null
+++ b/src/main/java/com/ql/util/express/parse/KeyWordDefine4SQL.java
@@ -0,0 +1,73 @@
+package com.ql.util.express.parse;
+
+
+public class KeyWordDefine4SQL {
+ public String[] splitWord={
+ "+", "-","*", "/",//四则运算:
+ ".",",",":",";","(", ")","[", "]","{","}","?",//分隔符号
+ "!","<", ">", "<=", ">=", "<>","="
+ };
+ public String[] keyWords = new String[] {
+ "select","from","where","and","or","like","if","then","else","as"
+ };
+ public String[] nodeTypeDefines = new String[] {
+ "in:TYPE=KEYWORD",
+ "EOF:TYPE=WORDDEF",
+ "FUNCTION_NAME:TYPE=WORDDEF",
+ "FUNCTION_DEFINE:TYPE=WORDDEF",
+ "ID:TYPE=WORDDEF",
+ "LEFT_BRACKET:TYPE=WORDDEF,DEFINE=(",
+ "RIGHT_BRACKET:TYPE=WORDDEF,DEFINE=)",
+
+ "CONST_BYTE:TYPE=WORDDEF",
+ "CONST_SHORT:TYPE=WORDDEF",
+ "CONST_INTEGER:TYPE=WORDDEF",
+ "CONST_LONG:TYPE=WORDDEF",
+ "CONST_FLOAT:TYPE=WORDDEF",
+ "CONST_DOUBLE:TYPE=WORDDEF",
+ "CONST_NUMBER:TYPE=WORDDEF,DEFINE=CONST_BYTE|CONST_SHORT|CONST_INTEGER|CONST_LONG|CONST_FLOAT|CONST_DOUBLE",
+ "CONST_CHAR:TYPE=WORDDEF",
+ "CONST_STRING:TYPE=WORDDEF",
+ "CONST_BOOLEAN:TYPE=WORDDEF",
+ "CONST_CLASS:TYPE=WORDDEF",
+ "CONST:TYPE=GROUP,DEFINE=CONST_NUMBER|CONST_CHAR|CONST_STRING|CONST_BOOLEAN|CONST_CLASS",
+
+// "():TYPE=BLOCK,STARTTAG=(,ENDTAG=)",
+// "[]:TYPE=BLOCK,STARTTAG=[,ENDTAG=]",
+// "{}:TYPE=BLOCK,STARTTAG={,ENDTAG=}",
+// "EXPRESS_CHILD:TYPE=GROUP,DEFINE=()|[]",
+
+ "OP_LEVEL1:TYPE=OPERATOR,DEFINE=!",
+ "OP_LEVEL2:TYPE=OPERATOR,DEFINE=*|/",
+ "OP_LEVEL3:TYPE=OPERATOR,DEFINE=+|-",
+ "OP_LEVEL4:TYPE=OPERATOR,DEFINE=in|like",
+ "OP_LEVEL5:TYPE=OPERATOR,DEFINE=>|>=|<|<=|=|<>",
+ "OP_LEVEL6:TYPE=OPERATOR,DEFINE=and",
+ "OP_LEVEL7:TYPE=OPERATOR,DEFINE=or",
+
+ "TAB_COL_NAME:TYPE=STATEMENT,DEFINE=ID$(.$ID)*#TAB_COL_NAME",
+ "CHILD_EXPRESS:TYPE=EXPRESS,DEFINE=LEFT_BRACKET~$EXPRESS$RIGHT_BRACKET~",
+ "OPDATA:TYPE=EXPRESS,DEFINE=CHILD_EXPRESS|CONST|TAB_COL_NAME",
+ "TAB_COL_NAME_ALIAS:TYPE=STATEMENT,DEFINE=TAB_COL_NAME$(as^$TAB_COL_NAME){0:1}",
+ "TAB_COL_LIST:TYPE=STATEMENT,DEFINE=TAB_COL_NAME_ALIAS$(,~$TAB_COL_NAME_ALIAS)*",
+
+ "EXPRESS_OP_L1:TYPE=EXPRESS,DEFINE=OP_LEVEL1^*$OPDATA",
+ "EXPRESS_OP_L2:TYPE=EXPRESS,DEFINE=EXPRESS_OP_L1$(OP_LEVEL2^$EXPRESS_OP_L1)^*",
+ "EXPRESS_OP_L3:TYPE=EXPRESS,DEFINE=EXPRESS_OP_L2$(OP_LEVEL3^$EXPRESS_OP_L2)^*",
+ "EXPRESS_OP_L4:TYPE=EXPRESS,DEFINE=EXPRESS_OP_L3$(OP_LEVEL4^$EXPRESS_OP_L3)^*",
+ "EXPRESS_OP_L5:TYPE=EXPRESS,DEFINE=EXPRESS_OP_L4$(OP_LEVEL5^$EXPRESS_OP_L4)^*",
+ "EXPRESS_OP_L6:TYPE=EXPRESS,DEFINE=EXPRESS_OP_L5$(OP_LEVEL6^$EXPRESS_OP_L5)^*",
+ "EXPRESS_OP_L7:TYPE=EXPRESS,DEFINE=EXPRESS_OP_L6$(OP_LEVEL7^$EXPRESS_OP_L6)^*",
+
+ "EXPRESS:TYPE=STATEMENT,DEFINE=EXPRESS_OP_L7",
+
+ "OP_LIST:TYPE=GROUP,DEFINE=OP_LEVEL1|OP_LEVEL2|OP_LEVEL3|OP_LEVEL4|OP_LEVEL5|OP_LEVEL6|OP_LEVEL7|LEFT_BRACKET|RIGHT_BRACKET|[|]",
+ "PARAMETER_LIST:TYPE=STATEMENT,DEFINE=EXPRESS$(,~$EXPRESS)*",
+ "SELECT:TYPE=STATEMENT,DEFINE=(select^$TAB_COL_LIST)$(from^$PARAMETER_LIST)$(where^$EXPRESS){0:1}#SELECT",
+
+ "STATEMENT:TYPE=STATEMENT",
+ "PROGRAM:TYPE=STATEMENT,DEFINE=SELECT",
+
+
+ };
+}
diff --git a/src/main/java/com/ql/util/express/parse/NodeType.java b/src/main/java/com/ql/util/express/parse/NodeType.java
new file mode 100644
index 0000000000000000000000000000000000000000..34ba0b975c56032638e3062ba8dbac0eae61eda6
--- /dev/null
+++ b/src/main/java/com/ql/util/express/parse/NodeType.java
@@ -0,0 +1,165 @@
+package com.ql.util.express.parse;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.ql.util.express.match.INodeType;
+import com.ql.util.express.match.QLPattern;
+import com.ql.util.express.match.QLPatternNode;
+
+enum NodeTypeKind {
+ KEYWORD, BLOCK, EXPRESS, OPERATOR, WORDDEF, GROUP, STATEMENT
+}
+
+public class NodeType implements INodeType {
+ NodeTypeManager manager;
+ private String name;
+ private String defineStr;
+ private NodeTypeKind kind;
+ private NodeType realNodeType;
+ private String instructionFactory;
+ /**
+ * 模式匹配
+ */
+ private QLPatternNode qlPatternNode;
+
+ protected NodeType(NodeTypeManager aManager, String aName, String aDefineStr) {
+ this.manager = aManager;
+ this.defineStr = aDefineStr;
+ this.name = aName;
+ }
+
+ public static String[][] splitProperties(String str) {
+ Pattern p = Pattern.compile("(,|:)\\s*(([A-Z]|-|_)*)\\s*=");
+ Matcher matcher = p.matcher(str);
+ List list = new ArrayList();
+ int endIndex = 0;
+ while (matcher.find()) {
+ if (list.size() > 0) {
+ list.get(list.size() - 1)[1] = str.substring(endIndex,
+ matcher.start()).trim();
+ }
+ list.add(new String[2]);
+ list.get(list.size() - 1)[0] = str.substring(matcher.start() + 1,
+ matcher.end() - 1).trim();
+ endIndex = matcher.end();
+ }
+ if (list.size() > 0) {
+ list.get(list.size() - 1)[1] = str.substring(endIndex).trim();
+ }
+ return (String[][]) list.toArray(new String[0][2]);
+ }
+
+ public void initial() {
+ try {
+ int index = this.defineStr.indexOf(":", 1);
+ String[][] properties = splitProperties(this.defineStr.substring(index));
+ for (String[] tempList : properties) {
+ if (tempList[0].equalsIgnoreCase("type")) {
+ this.setKind(NodeTypeKind.valueOf(tempList[1]));
+ } else if (tempList[0].equalsIgnoreCase("real")) {
+ this.realNodeType = manager.findNodeType(tempList[1]);
+ } else if (tempList[0].equalsIgnoreCase("factory")) {
+ this.instructionFactory = tempList[1];
+ } else if (tempList[0].equalsIgnoreCase("define")) {
+ this.qlPatternNode = QLPattern.createPattern(this.manager,
+ this.name, tempList[1]);
+ } else {
+ throw new RuntimeException("不能识别\"" + this.name
+ + "\"的属性类型:" + tempList[0] + " 定义:"
+ + this.defineStr);
+ }
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("节点类型\"" + this.name + "\"初始化失败,定义:"
+ + this.defineStr, e);
+ }
+ }
+ public boolean isEqualsOrChild(String parent) {
+ return this.manager.findNodeType(parent).isContainerChild(this);
+ }
+
+ public boolean isContainerChild(NodeType child) {
+ if (this.equals(child)) {
+ return true;
+ }
+ if (this.qlPatternNode == null) {
+ return false;
+ }
+ if (this.qlPatternNode.isDetailMode()) {
+ return ((NodeType) this.qlPatternNode.getNodeType())
+ .isContainerChild(child);
+ }
+ // 是and类型,不能增加子节点或进行判断
+ if (this.qlPatternNode.isAndMode()
+ && this.qlPatternNode.getChildren().size() > 0) {
+ return false;
+ }
+ for (QLPatternNode node : this.qlPatternNode.getChildren()) {
+ if (node.getNodeType() != null
+ && ((NodeType) node.getNodeType()).isContainerChild(child)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void addChild(NodeType child) throws Exception {
+ String str = child.name;
+ if (this.qlPatternNode != null) {
+ str = this.qlPatternNode.toString() + "|" + str;
+ }
+ this.qlPatternNode = QLPattern.createPattern(this.manager, this.name,str);
+ }
+
+ public String toString() {
+ StringBuilder result = new StringBuilder();
+ result.append(name + ":TYPE=" + this.kind);
+ if (this.instructionFactory != null) {
+ result.append(",FACTORY=" + this.instructionFactory);
+ }
+ if (this.qlPatternNode != null) {
+ result.append(",DEFINE=").append(this.qlPatternNode);
+ }
+ return result.toString();
+ }
+
+ public NodeType getRealNodeType() {
+ return realNodeType;
+ }
+
+ public NodeTypeKind getKind() {
+ return kind;
+ }
+
+ public String getInstructionFactory() {
+ return instructionFactory;
+ }
+
+ public void setInstructionFactory(String instructionFactory) {
+ this.instructionFactory = instructionFactory;
+ }
+
+ public NodeTypeManager getManager() {
+ return manager;
+ }
+
+ public String getDefineStr() {
+ return defineStr;
+ }
+ public void setKind(NodeTypeKind kind) {
+ this.kind = kind;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+
+ public QLPatternNode getPatternNode() {
+ return this.qlPatternNode;
+ }
+
+}
diff --git a/src/main/java/com/ql/util/express/parse/NodeTypeManager.java b/src/main/java/com/ql/util/express/parse/NodeTypeManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..cb257eded9af344eba07692cd644299f8aa5fba0
--- /dev/null
+++ b/src/main/java/com/ql/util/express/parse/NodeTypeManager.java
@@ -0,0 +1,173 @@
+package com.ql.util.express.parse;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import com.ql.util.express.match.INodeTypeManager;
+
+public class NodeTypeManager implements INodeTypeManager {
+ private static final Log log = LogFactory.getLog(NodeTypeManager.class);
+
+ public String[] splitWord;
+ private String[] keyWords;
+ private String[] nodeTypeDefines;
+ protected String[][] instructionFacotryMapping;
+ protected Map nodeTypes = new HashMap();
+
+ //所有的函数定义
+ protected Map functions = new HashMap();
+
+ public NodeTypeManager() {
+ this(new KeyWordDefine4Java());
+ }
+ public NodeTypeManager(KeyWordDefine4SQL keyWorkdDefine){
+ this.splitWord = keyWorkdDefine.splitWord;
+ this.keyWords = keyWorkdDefine.keyWords;
+ this.nodeTypeDefines = keyWorkdDefine.nodeTypeDefines;
+ this.initial();
+
+ }
+ public NodeTypeManager(KeyWordDefine4Java keyWorkdDefine){
+ this.splitWord = keyWorkdDefine.splitWord;
+ com.ql.util.express.parse.WordSplit.sortSplitWord(this.splitWord);
+ this.keyWords = keyWorkdDefine.keyWords;
+ this.nodeTypeDefines = keyWorkdDefine.nodeTypeDefines;
+ this.instructionFacotryMapping = keyWorkdDefine.instructionFacotryMapping;
+ this.initial();
+ this.addOperatorWithRealNodeType("and","&&");
+ this.addOperatorWithRealNodeType("or","||");
+
+ }
+
+ public void initial() {
+ //创建所有的关键字
+ NodeType[] tempKeyWordNodeTypes = new NodeType[splitWord.length + keyWords.length];
+ for (int i = 0; i < splitWord.length; i++) {
+ tempKeyWordNodeTypes[i] = this.createNodeType(splitWord[i] + ":TYPE=KEYWORD");
+ }
+ for (int i = 0 ; i < keyWords.length; i++) {
+ tempKeyWordNodeTypes[i + splitWord.length] = this.createNodeType(keyWords[i] + ":TYPE=KEYWORD");
+ }
+ // 初始化所有的类型信息,
+ for (int i = 0; i < tempKeyWordNodeTypes.length; i++) {
+ tempKeyWordNodeTypes[i].initial();
+ }
+
+ // 创建所有的类型信息,但不能初始化
+ NodeType[] nodeTypes = new NodeType[nodeTypeDefines.length];
+ for (int i = 0; i < nodeTypeDefines.length; i++) {
+ nodeTypes[i] = this.createNodeType(nodeTypeDefines[i]);
+ }
+ // 初始化所有的类型信息,
+ for (int i = 0; i < nodeTypes.length; i++) {
+ nodeTypes[i].initial();
+ }
+
+ //初始化指令Facotry
+ if (this.instructionFacotryMapping != null) {
+ for (String[] list : this.instructionFacotryMapping) {
+ for (String s : list[0].split(",")) {
+ this.findNodeType(s).setInstructionFactory(list[1]);
+ }
+ }
+ }
+ }
+
+ /**
+ * 创建节点类型,需要注意的是不能初始化,必须所有的类型都创建完成后才能调用初始化方法
+ * @param aDefineStr
+ * @return
+ */
+ public NodeType createNodeType(String aDefineStr){
+ int index = aDefineStr.indexOf(":",1);//避免对操作符号":"的错误处理
+ String name = aDefineStr.substring(0,index).trim();
+ NodeType define = nodeTypes.get(name);
+ if(define != null ){
+ log.warn("节点类型定义重复:"+name+" 定义1="+define.getDefineStr() + " 定义2=" + aDefineStr);
+ throw new RuntimeException("节点类型定义重复:"+name+" 定义1="+define.getDefineStr() + " 定义2=" + aDefineStr);
+ }
+ define = new NodeType(this,name,aDefineStr);
+ nodeTypes.put(name, define);
+ return define;
+ }
+ /**
+ * 根据类型名称查找节点类型
+ * @param name
+ * @return
+ */
+ @Override
+ public NodeType findNodeType(String name){
+ NodeType result = nodeTypes.get(name);
+ if(result == null){
+ throw new RuntimeException("没有定义的节点类型:" + name);
+ }
+ while(result.getRealNodeType() != null){
+ result = result.getRealNodeType();
+ }
+ return result;
+ }
+
+ /**
+ * 增加关键字,但是用实际的类型代替,例如 :"如果"->"if"
+ * @param keyWordName
+ * @param realName
+ */
+ public void addOperatorWithRealNodeType(String keyWordName, String realName){
+ NodeType target = this.createNodeType(keyWordName + ":TYPE=KEYWORD,REAL=" + realName);
+ target.initial();
+ }
+
+ /**
+ * 增加新的操作符号,其优先级别,以及语法关系与参照的操作符号一致
+ * @param operName
+ * @param refOperName
+ * @throws Exception
+ */
+ public void addOperatorWithLevelOfReference(String operName, String refOperName) throws Exception{
+ NodeType target = this.createNodeType(operName + ":TYPE=KEYWORD");
+ target.initial();
+ NodeType[] list = this.getNodeTypesByKind(NodeTypeKind.OPERATOR);
+ NodeType refNodeType = this.findNodeType(refOperName);
+ target.setInstructionFactory(refNodeType.getInstructionFactory());
+ for(NodeType item:list){
+ if(item.isContainerChild(refNodeType)){
+ item.addChild(target);
+ return;
+ }
+ }
+ }
+
+ /**
+ * 判断是否存在节点类型定义
+ * @param name
+ * @return
+ */
+ public NodeType isExistNodeTypeDefine(String name){
+ NodeType result = nodeTypes.get(name);
+ if(result != null && result.getRealNodeType() != null){
+ result = result.getRealNodeType();
+ }
+ return result;
+ }
+
+ public NodeType[] getNodeTypesByKind(NodeTypeKind aKind){
+ List result = new ArrayList();
+ for(NodeType item :this.nodeTypes.values()){
+ if(item.getKind() == aKind){
+ result.add(item);
+ }
+ }
+ return result.toArray(new NodeType[0]);
+ }
+ public boolean isFunction(String name){
+ return this.functions.containsKey(name);
+ }
+ public void addFunctionName(String name){
+ this.functions.put(name, name);
+ }
+}
diff --git a/src/main/java/com/ql/util/express/parse/Word.java b/src/main/java/com/ql/util/express/parse/Word.java
new file mode 100644
index 0000000000000000000000000000000000000000..cfae250578e26e885861e96e54a5b066c7d50b09
--- /dev/null
+++ b/src/main/java/com/ql/util/express/parse/Word.java
@@ -0,0 +1,16 @@
+package com.ql.util.express.parse;
+
+
+public class Word {
+ public String word;
+ public int line;
+ public int col;
+ public Word(String aWord,int aLine,int aCol){
+ this.word = aWord;
+ this.line = aLine;
+ this.col = aCol - aWord.length() + 1;
+ }
+ public String toString(){
+ return this.word;// + "[" + this.line + "," + this.col + "]";
+ }
+}
diff --git a/src/main/java/com/ql/util/express/parse/WordSplit.java b/src/main/java/com/ql/util/express/parse/WordSplit.java
new file mode 100644
index 0000000000000000000000000000000000000000..8383e0868e33a12228c8744e6685ae5271c74972
--- /dev/null
+++ b/src/main/java/com/ql/util/express/parse/WordSplit.java
@@ -0,0 +1,142 @@
+
+package com.ql.util.express.parse;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+
+
+/**
+ * 语法解析类
+ * 1、单词分解
+ * @author xuannan
+ *
+ */
+
+public class WordSplit
+{
+ /**
+ * 文本分析函数,“.”作为操作符号处理
+ * @param str String
+ * @throws Exception
+ * @return String[]
+ */
+ public static Word[] parse(String[] splitWord,String str) throws Exception{
+ if (str == null){
+ return new Word[0];
+ }
+ char c;
+ int line =1;
+ List list = new ArrayList();
+ int i= 0;
+ int point = 0;
+ while(i0 && str.charAt(index - 1) =='\\'){
+ index = str.indexOf(c,index + 1);
+ }
+ if (index < 0)
+ throw new Exception("字符串没有关闭");
+ String tempDealStr = str.substring(i,index + 1);
+ //处理 \\,\"的情况
+ String tmpResult = "";
+ int tmpPoint = tempDealStr.indexOf("\\");
+ while(tmpPoint >=0 ){
+ tmpResult = tmpResult + tempDealStr.substring(0,tmpPoint);
+ if(tmpPoint == tempDealStr.length() -1){
+ throw new Exception("字符串中的" + "\\错误:" + tempDealStr);
+ }
+ tmpResult = tmpResult + tempDealStr.substring(tmpPoint + 1 ,tmpPoint + 2);
+ tempDealStr = tempDealStr.substring(tmpPoint + 2);
+ tmpPoint = tempDealStr.indexOf("\\");
+ }
+ tmpResult = tmpResult + tempDealStr;
+ list.add(new Word(tmpResult,line,i));
+
+ if (point < i ){
+ list.add(new Word(str.substring(point,i),line,i));
+ }
+ i = index + 1;
+ point = i;
+ }else if(c=='.' && point < i && isNumber(str.substring(point,i))){
+ i = i + 1; //小数点的特殊处理
+ }else if(c == ' ' ||c =='\r'|| c =='\n'||c=='\t'||c=='\u000C'){
+ if (point < i ){
+ list.add(new Word(str.substring(point,i),line,i));
+ }
+ if(c =='\n'){
+ line = line + 1;
+ }
+ i = i + 1;
+ point = i;
+ }else{
+ boolean isFind = false;
+ for(String s:splitWord){
+ int length = s.length();
+ if(i + length <= str.length() && str.substring(i, i+length).equals(s)){
+ if (point < i ){
+ list.add(new Word(str.substring(point,i),line,i));
+ }
+ list.add(new Word(str.substring(i, i+length),line,i));
+ i = i + length;
+ point = i;
+ isFind = true;
+ break;
+ }
+ }
+ if(isFind == false){
+ i = i+1;
+ }
+ }
+ }
+ if (point < i) {
+ list.add(new Word(str.substring(point, i), line, i));
+ }
+
+ Word result[] = new Word[list.size()];
+ list.toArray(result);
+ return result;
+ }
+
+ public static String[] sortSplitWord(String[] splitWord) {
+ Arrays.sort(splitWord, new Comparator() {
+ public int compare(String o1, String o2) {
+ if (o1.length() == o2.length()) {
+ return 0;
+ } else if (o1.length() > o2.length()) {
+ return -1;
+ } else {
+ return 1;
+ }
+
+ }
+ });
+ return splitWord;
+ }
+
+ protected static boolean isNumber(String str) {
+ if (str == null || str.equals(""))
+ return false;
+ char c = str.charAt(0);
+ if (c >= '0' && c <= '9') { // 数字
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+
+ public static String getPrintInfo(Object[] list,String splitOp){
+ StringBuffer buffer = new StringBuffer();
+ for(int i=0;i 0){buffer.append(splitOp);}
+ buffer.append("{" + list[i] +"}");
+ }
+ return buffer.toString();
+ }
+
+}
diff --git a/src/test/java/com/ql/util/express/bugfix/CrashTest.java b/src/test/java/com/ql/util/express/bugfix/CrashTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..de269c316750cd98239fdde28dd9a5e548d3dee9
--- /dev/null
+++ b/src/test/java/com/ql/util/express/bugfix/CrashTest.java
@@ -0,0 +1,73 @@
+package com.ql.util.express.bugfix;
+
+import com.ql.util.express.parse.WordSplit;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.CyclicBarrier;
+
+/**
+ * Created by tianqiao on 16/11/10.
+ */
+public class CrashTest {
+
+
+ @Test
+ public void helloworld()
+ {
+
+ }
+
+
+ public static String[] splitWord={
+ "~","&","|","<<", ">>",//位操作
+ "+", "-","*", "/", "%","++", "--",//四则运算:
+ ".",",",":",";","(", ")", "{", "}", "[", "]","?",//分隔符号
+ "!","<", ">", "<=", ">=", "==","!=","&&","||",//Boolean运算符号
+ "=","/**","**/"
+ };
+
+ /**
+ * 版本3.0.9以下存在多线程初始化问题,这个类作为一个样例
+ */
+ public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
+ System.out.println(Arrays.asList(splitWord));
+ for (int j = 0; j < 1000; j++) {
+ CyclicBarrier barrier = new CyclicBarrier(11, null);
+ for (int i = 0; i < 10; i++) {
+ Thread t = new Thread(new Worker(barrier), "t" + i);
+ t.start();
+ }
+ Thread.sleep(500);
+ barrier.await();
+ while (barrier.getNumberWaiting() > 0) {
+ Thread.sleep(1000);
+ }
+ Thread.sleep(1000);
+ System.out.println(Arrays.asList(splitWord));
+ }
+ }
+
+ static class Worker implements Runnable {
+
+ private CyclicBarrier barrier;
+
+ public Worker(CyclicBarrier b){
+ this.barrier = b;
+ }
+
+ public void run() {
+ try {
+
+ barrier.await();
+
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ } catch (BrokenBarrierException e) {
+ e.printStackTrace();
+ }
+ WordSplit.sortSplitWord(splitWord);
+ }
+ }
+}
diff --git a/src/test/java/com/ql/util/express/bugfix/SerializeTest.java b/src/test/java/com/ql/util/express/bugfix/SerializeTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..8dd5340a61bd408165ae63413b208c03f47a62ae
--- /dev/null
+++ b/src/test/java/com/ql/util/express/bugfix/SerializeTest.java
@@ -0,0 +1,116 @@
+package com.ql.util.express.bugfix;
+
+import com.ql.util.express.ExpressRunner;
+import com.ql.util.express.InstructionSet;
+import org.junit.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+
+public class SerializeTest {
+
+ @Test
+ public void Test() throws Exception {
+ ExpressRunner runner = new ExpressRunner();
+ try {
+ /*
+ * 添加一个规则方法
+ * */
+ runner.addFunctionOfClassMethod("getS", TestExpress.class.getName(),
+ "getScore", new String[]{TestData.class.getName()}, null);
+ /*
+ * 添加一个规则宏
+ * */
+ runner.addMacro("获取分数宏", "getS(testInfo)");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ byte[] bytes1 = null;
+ byte[] bytes2 = null;
+ byte[] bytes3 = null;
+
+ String express1 = "获取分数宏";
+ String express2 = "getS(testInfo)";
+ String express3 = "int score = getS(testInfo)";
+
+ /*
+ * 根据两种不同的规则文本获取指令集
+ * */
+ InstructionSet is1 = runner.parseInstructionSet(express1);
+ InstructionSet is2 = runner.parseInstructionSet(express2);
+ InstructionSet is3 = runner.parseInstructionSet(express3);
+
+ /*
+ * 对指令集进行序列化
+ * */
+ testSerialize(is1);
+ testSerialize(is2);
+ testSerialize(is3);
+
+ }
+
+ private void testSerialize(InstructionSet is)
+ {
+ int len = is.getInstructionLength();
+ for(int i=0;i expressContext = new DefaultContext();
+ expressContext.put("cust", new CustBean(1));
+ ExpressRunner runner = new ExpressRunner();
+ //执行表达式,并将结果赋给r
+ String r = (String)runner.execute(exp,expressContext,null,false,false);
+ System.out.println(r);
+ Assert.assertTrue("操作符执行错误","小强".equals(r));
+ }
+
+ @Test
+ public void test3() throws Exception{
+ String exp = "首字母大写(\"abcd\")";
+ ExpressRunner runner = new ExpressRunner();
+ runner.addFunctionOfClassMethod("首字母大写", CustBean.class.getName(), "firstToUpper", new String[]{"String"},null);
+ //执行表达式,并将结果赋给r
+ String r = (String)runner.execute(exp,null,null,false,false);
+ System.out.println(r);
+ Assert.assertTrue("操作符执行错误","Abcd".equals(r));
+ }
+
+ /**
+ * 使用别名
+ * @throws Exception
+ */
+ @Test
+ public void testAlias() throws Exception{
+ String exp = "cust.setName(\"小强\");" +
+ "定义别名 custName cust.name;" +
+ "return custName;";
+ IExpressContext expressContext = new DefaultContext();
+ expressContext.put("cust", new CustBean(1));
+ ExpressRunner runner = new ExpressRunner();
+ //
+ runner.addOperatorWithAlias("定义别名", "alias", null);
+ //执行表达式,并将结果赋给r
+ String r = (String)runner.execute(exp,expressContext,null,false,false);
+ System.out.println(r);
+ Assert.assertTrue("操作符执行错误","小强".equals(r));
+ }
+
+ /**
+ * 使用宏
+ * @throws Exception
+ */
+ @Test
+ public void testMacro() throws Exception{
+ String exp = "cust.setName(\"小强\");" +
+ "定义宏 custName {cust.name};" +
+ "return custName;";
+ IExpressContext expressContext = new DefaultContext();
+ expressContext.put("cust", new CustBean(1));
+ ExpressRunner runner = new ExpressRunner();
+ //
+ runner.addOperatorWithAlias("定义宏", "macro", null);
+ //执行表达式,并将结果赋给r
+ String r = (String)runner.execute(exp,expressContext,null,false,false);
+ System.out.println(r);
+ Assert.assertTrue("操作符执行错误","小强".equals(r));
+ }
+}
diff --git a/src/test/java/com/ql/util/express/example/CustBean.java b/src/test/java/com/ql/util/express/example/CustBean.java
new file mode 100644
index 0000000000000000000000000000000000000000..672b2416ea1ab432865c398bd51dcd8e16142e2f
--- /dev/null
+++ b/src/test/java/com/ql/util/express/example/CustBean.java
@@ -0,0 +1,45 @@
+package com.ql.util.express.example;
+
+import org.apache.commons.lang.StringUtils;
+
+public class CustBean {
+
+ long id;
+ String name;
+ int age;
+
+ public CustBean(long id){
+ this.id = id;
+ }
+
+ public long getId() {
+ return id;
+ }
+ public void setId(long id) {
+ this.id = id;
+ }
+ public String getName() {
+ return name;
+ }
+ public void setName(String name) {
+ this.name = name;
+ }
+ public int getAge() {
+ return age;
+ }
+ public void setAge(int age) {
+ this.age = age;
+ }
+
+ public static String firstToUpper(String value){
+ if(StringUtils.isBlank(value))
+ return "";
+ value = StringUtils.trim(value);
+ String f = StringUtils.substring(value,0,1);
+ String s = "";
+ if(value.length() > 1){
+ s = StringUtils.substring(value,1);
+ }
+ return f.toUpperCase() + s;
+ }
+}
diff --git a/src/test/java/com/ql/util/express/example/OperatorTest.java b/src/test/java/com/ql/util/express/example/OperatorTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..eaf74c666fc94b3a4a9416a5e78ae146e35467ee
--- /dev/null
+++ b/src/test/java/com/ql/util/express/example/OperatorTest.java
@@ -0,0 +1,89 @@
+package com.ql.util.express.example;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.ql.util.express.DefaultContext;
+import com.ql.util.express.ExpressRunner;
+import com.ql.util.express.IExpressContext;
+import com.ql.util.express.example.operator.AddNOperator;
+import com.ql.util.express.example.operator.AddTwiceOperator;
+
+/**
+ * 本例用于展示如何自定义操作符和方法
+ *
+ */
+public class OperatorTest {
+
+ /**
+ * 定义一个简单的二元操作符
+ * @throws Exception
+ */
+ @Test
+ public void testAddTwice() throws Exception{
+ //定义表达式,相当于 1+(22+22)+(2+2)
+ String exp = " 1 addT 22 addT 2";
+ ExpressRunner runner = new ExpressRunner();
+ //定义操作符addT,其实现为AddTwiceOperator
+ runner.addOperator("addT", new AddTwiceOperator());
+ //执行表达式,并将结果赋给r
+ int r = (Integer)runner.execute(exp,null,null,false,false);
+ System.out.println(r);
+ Assert.assertTrue("操作符执行错误",r==49);
+ }
+
+ /**
+ * 定义一个多元操作符
+ * @throws Exception
+ */
+ @Test
+ public void testAddNByOperator() throws Exception{
+ //定义表达式,相当于4+1+2+3
+ String exp = "4 addN (1,2,3)";
+ ExpressRunner runner = new ExpressRunner();
+ //定义操作符addN,其实现为AddNOperator,语法格式与in一致
+ runner.addOperator("addN","in",new AddNOperator());
+ //执行表达式,并将结果赋给r
+ int r = (Integer)runner.execute(exp,null,null,false,false);
+ System.out.println(r);
+ Assert.assertTrue("操作符执行错误",r==10);
+ }
+
+ /**
+ * 定义一个方法
+ * @throws Exception
+ */
+ @Test
+ public void testAddNByFunction() throws Exception{
+ //定义表达式,相当于1+2+3+4
+ String exp = "addN(1,2,3,4)";
+ ExpressRunner runner = new ExpressRunner();
+ //定义方法addN,其实现为AddNOperator
+ runner.addFunction("addN",new AddNOperator());
+ //执行表达式,并将结果赋给r
+ int r = (Integer)runner.execute(exp,null,null,false,false);
+ System.out.println(r);
+ Assert.assertTrue("操作符执行错误",r==10);
+ }
+
+ /**
+ * 使用参数
+ * @throws Exception
+ */
+ @Test
+ public void testAddTwiceWithParams() throws Exception{
+ //定义表达式,相当于 i+(j+j)+(n+n)
+ String exp = " i addT j addT n";
+ IExpressContext expressContext = new DefaultContext();
+ expressContext.put("i", Integer.valueOf(1));
+ expressContext.put("j", Integer.valueOf(22));
+ expressContext.put("n", Integer.valueOf(2));
+ ExpressRunner runner = new ExpressRunner();
+ //定义操作符addT,其实现为AddTwiceOperator
+ runner.addOperator("addT", new AddTwiceOperator());
+ //执行表达式,并将结果赋给r
+ int r = (Integer)runner.execute(exp,expressContext,null,false,false);
+ System.out.println(r);
+ Assert.assertTrue("操作符执行错误",r==49);
+ }
+}
diff --git a/src/test/java/com/ql/util/express/example/TypicalDemo.java b/src/test/java/com/ql/util/express/example/TypicalDemo.java
new file mode 100644
index 0000000000000000000000000000000000000000..82bff32b9e8ad7a88185107a7a086bdbe73ec0ff
--- /dev/null
+++ b/src/test/java/com/ql/util/express/example/TypicalDemo.java
@@ -0,0 +1,107 @@
+package com.ql.util.express.example;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.ql.util.express.DefaultContext;
+import com.ql.util.express.ExpressRunner;
+import com.ql.util.express.IExpressContext;
+
+/**
+ * QLExpress的一种典型应用场景
+ * @author xuannan
+ *
+ */
+public class TypicalDemo {
+
+ private ExpressRunner runner = new ExpressRunner();
+ /**
+ * 判断一个用户TAG的第X位是否为1。这个的demo,其实现合理性不考虑
+ * @param user
+ * @param tagBitIndex
+ * @return
+ */
+ public boolean userTagJudge(UserInfo user,int tagBitIndex){
+ boolean r = (user.getUserTag() & ((long)Math.pow(2, tagBitIndex))) > 0;
+ return r;
+ }
+
+ /**
+ * 判断一个用户是否订购过某个商品
+ * @param user
+ * @param goodsId
+ * @return
+ */
+ public boolean hasOrderGoods(UserInfo user,long goodsId){
+ //随机模拟一个
+ if(user.getUserId() % 2 == 1){
+ return true;
+ }else{
+ return false;
+ }
+ }
+
+ /**
+ * 判断逻辑执行函数
+ * @param userInfo
+ * @param expression
+ * @return
+ * @throws Exception
+ */
+ public String hasPermission(UserInfo userInfo,String expression) throws Exception {
+ IExpressContext expressContext = new DefaultContext();
+ expressContext.put("userInfo",userInfo);
+ List errorInfo = new ArrayList();
+ Boolean result = (Boolean)runner.execute(expression, expressContext, errorInfo, true, false);
+ String resultStr ="";
+ if(result.booleanValue() == true){
+ resultStr = "可以订购此商品";
+ }else{
+ for(int i=0;i 0){
+ resultStr = resultStr + "," ;
+ }
+ resultStr = resultStr + errorInfo.get(i);
+ }
+ resultStr = resultStr + ",所以不能订购此商品";
+ }
+ return "亲爱的" + userInfo.getName() + " : " + resultStr;
+ }
+ public void initial() throws Exception{
+ runner.addOperatorWithAlias("而且","and",null);
+ runner.addFunctionOfClassMethod("userTagJudge", TypicalDemo.class.getName(), "userTagJudge",new String[] {UserInfo.class.getName(),"int"}, "你不是三星卖家");
+ runner.addFunctionOfClassMethod("hasOrderGoods", TypicalDemo.class.getName(), "hasOrderGoods",new String[] {UserInfo.class.getName(),"long"}, "你没有开通淘宝店铺");
+ runner.addMacro("三星卖家", "userTagJudge(userInfo,3)");//3表示三星卖家的标志位
+ runner.addMacro("已经开店", "hasOrderGoods(userInfo,100)");//100表示旺铺商品的ID
+ }
+ public static void main(String args[]) throws Exception{
+ TypicalDemo demo = new TypicalDemo();
+ demo.initial();
+ System.out.println(demo.hasPermission(new UserInfo(100,"xuannan",7), "三星卖家 而且 已经开店"));
+ System.out.println(demo.hasPermission(new UserInfo(101,"qianghui",8), "三星卖家 而且 已经开店"));
+ System.out.println(demo.hasPermission(new UserInfo(100,"张三",8), "三星卖家 and 已经开店"));
+ System.out.println(demo.hasPermission(new UserInfo(100,"李四",7), "三星卖家 and 已经开店"));
+ }
+}
+
+class UserInfo {
+ long id;
+ long tag;
+ String name;
+
+ public UserInfo(long aId,String aName, long aUserTag) {
+ this.id = aId;
+ this.tag = aUserTag;
+ this.name = aName;
+ }
+ public String getName(){
+ return name;
+ }
+ public long getUserId() {
+ return id;
+ }
+
+ public long getUserTag() {
+ return tag;
+ }
+}
diff --git a/src/test/java/com/ql/util/express/example/WorkflowTest.java b/src/test/java/com/ql/util/express/example/WorkflowTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..ffdc7f14ffcd6610254768de850616c4e1c22851
--- /dev/null
+++ b/src/test/java/com/ql/util/express/example/WorkflowTest.java
@@ -0,0 +1,154 @@
+package com.ql.util.express.example;
+
+import org.junit.Test;
+
+import com.ql.util.express.DefaultContext;
+import com.ql.util.express.ExpressRunner;
+import com.ql.util.express.IExpressContext;
+import com.ql.util.express.example.operator.ApproveOperator;
+
+/**
+ * 本例模拟了一个简单的流程处理
+ * 用于展示如何定义表达式,方法,并使用上下文变量
+ *
+ */
+public class WorkflowTest {
+
+ /**
+ * 执行一段文本
+ * @throws Exception
+ */
+ @Test
+ public void testApprove1()throws Exception{
+ //定义表达式
+ String exp = "如果 (审批通过(经理,金额)){" +
+ " 如果 (金额 大于 5000){ " +
+ " 如果 (审批通过(总监,金额)){" +
+ " 如果 (审批通过(财务,金额)){" +
+ " 报销入账(金额)" +
+ " }否则 {" +
+ " 打回修改(申请人)" +
+ " }" +
+ " }否则 {" +
+ " 打回修改(申请人)" +
+ " }" +
+ " }否则 {" +
+ " 如果 (审批通过(财务,金额)){" +
+ " 报销入账(金额)" +
+ " }否则 {" +
+ " 打回修改(申请人)" +
+ " }" +
+ " }" +
+ "}否则 {" +
+ " 打回修改(申请人)" +
+ "}" +
+ "打印(\"完成\")";
+ ExpressRunner runner = new ExpressRunner();
+ //定义操作符别名
+ runner.addOperatorWithAlias("如果", "if",null);
+ runner.addOperatorWithAlias("否则", "else",null);
+ runner.addOperatorWithAlias("大于", ">",null);
+ //
+ runner.addFunctionOfServiceMethod("打印", System.out, "println",new String[] { "String" }, null);
+ //定义方法
+ runner.addFunction("审批通过", new ApproveOperator(1));
+ runner.addFunction("报销入账", new ApproveOperator(2));
+ runner.addFunction("打回修改", new ApproveOperator(3));
+ //设置上下文变量
+ IExpressContext expressContext = new DefaultContext();
+ expressContext.put("经理", "王经理");
+ expressContext.put("总监", "李总监");
+ expressContext.put("财务", "张财务");
+ expressContext.put("申请人", "小强");
+ expressContext.put("金额", new Integer(4000));
+ //执行表达式
+ runner.execute(exp, expressContext, null,false, false);
+ }
+
+ /**
+ * 通过文件加载表达式
+ * @throws Exception
+ */
+ @Test
+ public void testApprove2()throws Exception{
+ ExpressRunner runner = new ExpressRunner();
+ //定义操作符别名
+ runner.addOperatorWithAlias("如果", "if",null);
+ runner.addOperatorWithAlias("否则", "else",null);
+ runner.addOperatorWithAlias("大于", ">",null);
+ //
+ runner.addFunctionOfServiceMethod("打印", System.out, "println",new String[] { "String" }, null);
+ //定义方法
+ runner.addFunction("审批通过", new ApproveOperator(1));
+ runner.addFunction("报销入账", new ApproveOperator(2));
+ runner.addFunction("打回修改", new ApproveOperator(3));
+ //加载文件
+ runner.loadExpress("example/approve1");
+ //从指定文件中获取表示式构造指令集
+
+ //设置上下文变量
+ IExpressContext expressContext = new DefaultContext();
+ expressContext.put("经理", "王经理");
+ expressContext.put("总监", "李总监");
+ expressContext.put("财务", "张财务");
+ expressContext.put("申请人", "小强");
+ expressContext.put("金额", new Integer(5000));
+
+ runner.executeByExpressName("example/approve1", expressContext, null, false,false,null);
+ }
+
+ /**
+ * 通过文件加载方法及表达式
+ * @throws Exception
+ */
+ @Test
+ public void testApprove3()throws Exception{
+ ExpressRunner runner = new ExpressRunner();
+ //定义操作符别名
+ runner.addOperatorWithAlias("如果", "if",null);
+ runner.addOperatorWithAlias("否则", "else",null);
+ runner.addOperatorWithAlias("大于", ">",null);
+ //
+ runner.addFunctionOfServiceMethod("打印", System.out, "println",new String[] { "String" }, null);
+ //加载文件
+ runner.loadExpress("example/approve");
+ //设置上下文变量
+ IExpressContext expressContext = new DefaultContext();
+ expressContext.put("经理", "王经理");
+ expressContext.put("总监", "李总监");
+ expressContext.put("财务", "张财务");
+ expressContext.put("申请人", "小强");
+ expressContext.put("金额", new Integer(6000));
+
+ runner.executeByExpressName("example/approve", expressContext, null, false,false,null);
+ }
+
+ /**
+ * 从不同的文件中加载方法及表达式
+ * @throws Exception
+ */
+ @Test
+ public void testApprove4()throws Exception{
+ ExpressRunner runner = new ExpressRunner();
+ //定义操作符别名
+ runner.addOperatorWithAlias("如果", "if",null);
+ runner.addOperatorWithAlias("否则", "else",null);
+ runner.addOperatorWithAlias("大于", ">",null);
+ //
+ runner.addFunctionOfServiceMethod("打印", System.out, "println",new String[] { "String" }, null);
+
+ //加载文件
+ runner.loadExpress("example/approve1");
+ runner.loadExpress("example/approve2");
+ //设置上下文变量
+ IExpressContext expressContext = new DefaultContext();
+ expressContext.put("经理", "王经理");
+ expressContext.put("总监", "李总监");
+ expressContext.put("财务", "张财务");
+ expressContext.put("申请人", "小强");
+ expressContext.put("金额", new Integer(7000));
+
+ runner.executeByExpressName("example/approve1", expressContext, null, false,false,null);
+ }
+
+}
diff --git a/src/test/java/com/ql/util/express/example/operator/AddNOperator.java b/src/test/java/com/ql/util/express/example/operator/AddNOperator.java
new file mode 100644
index 0000000000000000000000000000000000000000..5eefa6c9f26e0234b6ee82ec0196655ec4cd0a60
--- /dev/null
+++ b/src/test/java/com/ql/util/express/example/operator/AddNOperator.java
@@ -0,0 +1,18 @@
+package com.ql.util.express.example.operator;
+
+import com.ql.util.express.Operator;
+
+/**
+ * 定义连加的操作符
+ *
+ */
+public class AddNOperator extends Operator{
+
+ public Object executeInner(Object[] list) throws Exception {
+ int r = 0;
+ for(int i=0;i 6000)
+ return false;
+ }
+ else if(this.operater == 2)
+ System.out.println("报销入卡:金额:"+list[0]);
+ else
+ System.out.println("重填:申请人:"+list[0]);
+ return true;
+ }
+
+}
diff --git a/src/test/java/com/ql/util/express/test/AClassDefine.java b/src/test/java/com/ql/util/express/test/AClassDefine.java
new file mode 100644
index 0000000000000000000000000000000000000000..315f2328ace72ff42cf63294a18101897a2ae288
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/AClassDefine.java
@@ -0,0 +1,65 @@
+package com.ql.util.express.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.ql.util.express.DefaultContext;
+import com.ql.util.express.ExpressRunner;
+
+public class AClassDefine {
+
+ @Test
+ public void testNewVClass() throws Exception {
+ String express = "" +
+ "int a = 100;" +
+ "class ABC(){" +
+ " int a = 200;" +
+ " println a;" +
+ "}" +
+ "ABC abc = new ABC();" +
+ "println a + abc.a;" +
+ "return a + abc.a;";
+ ExpressRunner runner = new ExpressRunner(false, false);
+ DefaultContext context = new DefaultContext();
+ runner.loadMutilExpress("ClassTest", express);
+
+ Object r = runner.executeByExpressName("ClassTest", context,
+ null, false, false, null);
+ Assert.assertTrue("VClass的作用域错误", r.toString().equalsIgnoreCase("300"));
+ }
+ @Test
+ public void testABC() throws Exception {
+ String expressDefine =
+ "class ABC(com.ql.util.express.test.BeanExample bean,String name){"
+ + "姓名= name;"
+ + "计数器 = new InnerClass();"
+ + "整数值:bean.intValue;"
+ + "浮点值:bean.doubleValue;"
+ + "哈希值:{bean.hashCode();};"
+ + "function add(int a,int b){return a + b + 整数值 + 计数器.计数;};"
+ + "class InnerClass(){" +
+ "int 计数 =200;" +
+ "};"
+ + "};" ;
+ String express =
+ "ABC example = new ABC(new com.ql.util.express.test.BeanExample(),'xuannan');"
+ + "ABC example2 = new ABC(new com.ql.util.express.test.BeanExample(),'xuanyu');"
+ + " example.整数值 =100;"
+ + " example2.整数值 =200;"
+ + " example.浮点值= 99.99;"
+ + " example2.浮点值= 11.11;"
+ + " example.浮点值 = example.浮点值 + example.整数值;"
+ + " result = example.add(10,20) +'--'+ example2.add(10,20) +'--'+ example.姓名 +'--'+ example2.姓名 +'--'+ example.浮点值 +'--' + example2.浮点值 ;"
+ + " println result;"
+ + " return result ;"
+ + "";
+ ExpressRunner runner = new ExpressRunner(false, true);
+ DefaultContext context = new DefaultContext();
+ runner.loadMutilExpress("",expressDefine);
+ runner.loadMutilExpress("ClassTest", express);
+ Object r = runner.executeByExpressName("ClassTest", context,
+ null, false, false, null);
+ Assert.assertTrue("VClass的作用域错误", r.toString().equalsIgnoreCase("330--430--xuannan--xuanyu--199.99--11.11"));
+
+ }
+}
diff --git a/src/test/java/com/ql/util/express/test/AClassDefineSingle.java b/src/test/java/com/ql/util/express/test/AClassDefineSingle.java
new file mode 100644
index 0000000000000000000000000000000000000000..b811c2dde5cd536f8623dc4c0922220cf9d1bd35
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/AClassDefineSingle.java
@@ -0,0 +1,29 @@
+package com.ql.util.express.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.ql.util.express.DefaultContext;
+import com.ql.util.express.ExpressRunner;
+
+public class AClassDefineSingle {
+ @Test
+ public void testABC() throws Exception {
+ String expressDefine =
+ "class ABC(com.ql.util.express.test.BeanExample bean,String name){"
+ + "整数值:bean.intValue;"
+ + "};" ;
+ String express =
+ "ABC example = new ABC(new com.ql.util.express.test.BeanExample(),'xuannan');"
+ + " example.整数值 =100 + 100;"
+ + " print(example.整数值);"
+ + "";
+ ExpressRunner runner = new ExpressRunner(false, true);
+ DefaultContext context = new DefaultContext();
+ runner.loadMutilExpress("",expressDefine);
+ runner.loadMutilExpress("ClassTest", express);
+ Object r = runner.executeByExpressName("ClassTest", context,
+ null, true, false, null);
+
+ }
+}
diff --git a/src/test/java/com/ql/util/express/test/ATempTest.java b/src/test/java/com/ql/util/express/test/ATempTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..b3059d40fbfbfbb29d410de3de1870832944ad9e
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/ATempTest.java
@@ -0,0 +1,20 @@
+package com.ql.util.express.test;
+
+import org.junit.Test;
+
+import com.ql.util.express.DefaultContext;
+import com.ql.util.express.ExpressRunner;
+
+public class ATempTest {
+ @Test
+ public void test2Java() throws Exception {
+ //String express = "2 in (1,2,3)";
+ //String express = "include Test; max(1,2,3)";
+ String express = "when 1==2 then println(100000)";
+ ExpressRunner runner = new ExpressRunner(false,true);
+ DefaultContext context = new DefaultContext();
+ Object r = runner.execute(express, context, null, false,false);
+ System.out.println(r);
+ }
+
+}
diff --git a/src/test/java/com/ql/util/express/test/AddMacroDefineTest.java b/src/test/java/com/ql/util/express/test/AddMacroDefineTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..e8d4c089dfe1352a37682ecb7a069eeace20600d
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/AddMacroDefineTest.java
@@ -0,0 +1,20 @@
+package com.ql.util.express.test;
+
+import org.junit.Test;
+
+import com.ql.util.express.DefaultContext;
+import com.ql.util.express.ExpressRunner;
+
+public class AddMacroDefineTest {
+ @Test
+ public void test2Java() throws Exception {
+ ExpressRunner runner = new ExpressRunner(false,true);
+ runner.addFunctionOfClassMethod("abc", BeanExample.class.getName(),
+ "testLong", new String[] { "long" }, null);
+ runner.addMacro("玄难", "abc(100);");
+ String express = "玄难 + \" - Test\";";
+ DefaultContext context = new DefaultContext();
+ Object r = runner.execute(express, context, null, false,true);
+ System.out.println(r);
+ }
+}
diff --git a/src/test/java/com/ql/util/express/test/ArrayTest.java b/src/test/java/com/ql/util/express/test/ArrayTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..f3feb0e48fea24d416761cc2d81c53bb8e29063e
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/ArrayTest.java
@@ -0,0 +1,69 @@
+package com.ql.util.express.test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.ql.util.express.DefaultContext;
+import com.ql.util.express.ExpressRunner;
+import com.ql.util.express.IExpressContext;
+
+public class ArrayTest {
+
+ @Test
+ public void testABC() throws Exception {
+ String express = "int[][] abc = new int[2][2];"
+ + " int[] b = new int[2]; " + "abc[0] = b;" + " b[0] =11;"
+ + " abc[0][1] = 22; " + "return abc;";
+ ExpressRunner runner = new ExpressRunner();
+ DefaultContext context = new DefaultContext();
+ int[][] r = (int[][]) runner.execute(express, context, null, false,
+ true);
+ System.out.println(r[0][1]);
+ Assert.assertTrue("数组操作实现错误", r[0][1] == 22);
+ }
+
+ @Test
+ public void testAnonyNewArrayOrMapOrList() throws Exception {
+ ExpressRunner runner = new ExpressRunner(false, false);
+ String[][] expressTest = new String[][] {
+ {"int[] abc = [1,2,3];return abc[2]","3"},
+ {"int[][] abc = [[11,12,13],[21,22,23]];return abc[1][2]","23"},
+ {"String[] abc = [\"xuannan\",\"qianghui\"];return abc[1]","qianghui"},
+ {"String[] abc = [\"xuannan\"+100,\"qianghui\"+100];return abc[1]","qianghui100"},
+ {"Object[] abc = [];return abc.length","0"},
+ {"Map abc = NewMap(1:1,2:2); return abc.get(1) + abc.get(2)","3"},
+ {"Map abc = NewMap(\"a\":1,\"b\":2); return abc.a + abc.b","3"},
+ {"int o1 =10; int o2=20;String k1 =\"a\";String k2 =\"b\"; Map abc = NewMap(k1:o1,k2:o2); return abc.a + abc.b","30"},
+ {"Map abc = NewMap(1:\"xuannan\",2:\"qianghui\"); return abc.get(1) +\"-\"+ abc.get(2)","xuannan-qianghui"},
+ {"List abc = NewList(1,2,3); return abc.get(1)","2"},
+ };
+ IExpressContext expressContext = new ExpressContextExample(
+ null);
+
+ for (int point = 0; point < expressTest.length; point++) {
+ String expressStr = expressTest[point][0];
+ List errorList = new ArrayList();
+ Object result = runner.execute(expressStr, expressContext, null,
+ false, false);
+ if (result == null
+ && expressTest[point][1].equalsIgnoreCase("null") == false
+ || expressTest[point][1].equalsIgnoreCase("null")
+ && result != null
+ || result != null
+ && expressTest[point][1]
+ .equalsIgnoreCase(result.toString()) == false) {
+ throw new Exception("处理错误,计算结果与预期的不匹配:" + expressStr + " = "
+ + result + "但是期望值是:" + expressTest[point][1]);
+ }
+ System.out.println("Example " + point + " : " + expressStr + " = "
+ + result);
+ if (errorList.size() > 0) {
+ System.out.println("\t\t系统输出的错误提示信息:" + errorList);
+ }
+ }
+ System.out.println(expressContext);
+ }
+}
diff --git a/src/test/java/com/ql/util/express/test/BeanExample.java b/src/test/java/com/ql/util/express/test/BeanExample.java
new file mode 100644
index 0000000000000000000000000000000000000000..f5f7c7ebeb51e553289488cd1fc6fa9331ed2128
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/BeanExample.java
@@ -0,0 +1,88 @@
+package com.ql.util.express.test;
+
+public class BeanExample {
+ public String name = "qhlhl2010@gmail.com";
+ public int intValue;
+ public long longValue;
+ public double doubleValue;
+
+ public BeanExampleChild child = new BeanExampleChild();
+ public BeanExample() {
+ }
+ public static void printNumber(Number l,Number f){
+ System.out.println("f-------:" + l +'-'+ f);
+ }
+ public BeanExampleChild getChild() {
+ return child;
+ }
+
+ public int getIntValue() {
+ return intValue;
+ }
+
+ public void setIntValue(int intValue) {
+ this.intValue = intValue;
+ }
+
+ public String getText(String a,String b){
+ return a +"-" + b;
+ }
+ public String getText(String a,Long b){
+ return a +"-" + b;
+ }
+
+ public long getLongValue() {
+ return longValue;
+ }
+
+ public void setLongValue(long longValue) {
+ this.longValue = longValue;
+ }
+
+ public double getDoubleValue() {
+ return doubleValue;
+ }
+
+ public void setDoubleValue(double doubleValue) {
+ this.doubleValue = doubleValue;
+ }
+
+ public void setChild(BeanExampleChild child) {
+ this.child = child;
+ }
+ public String getName(){
+ return this.name;
+ }
+ public BeanExample(String aName) {
+ name = aName;
+ }
+ public String testLongObject(Long i){
+ return "toString-LongObject:" + i;
+ }
+ public String testLong(long i){
+ return "toString-long:" + i;
+ }
+ public String testInt(int i){
+ return "toString-int:" + i;
+ }
+ public String unionName(String otherName) {
+ //System.out.println(" execute unionName("+ otherName+ ") .....");
+ return name + "-" + otherName;
+ }
+
+ public static String upper(String abc) {
+ return abc.toUpperCase();
+ }
+
+ public static boolean isVIP(String name) {
+ //System.out.println(" execute isVIP("+ name+ ") .....");
+ return false;
+ }
+ public static boolean isVIPTwo(String name) {
+ //System.out.println(" execute isVIP("+ name+ ") .....");
+ return true;
+ }
+ public static boolean isVIPFalse() {
+ return false;
+ }
+}
diff --git a/src/test/java/com/ql/util/express/test/BeanExampleChild.java b/src/test/java/com/ql/util/express/test/BeanExampleChild.java
new file mode 100644
index 0000000000000000000000000000000000000000..f9428048c6b6f141826f37f6874d5cec1b642fdf
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/BeanExampleChild.java
@@ -0,0 +1,13 @@
+package com.ql.util.express.test;
+
+public class BeanExampleChild {
+ public String a ="qh";
+
+public String getA() {
+ return a;
+}
+
+public void setA(String a) {
+ this.a = a;
+}
+}
diff --git a/src/test/java/com/ql/util/express/test/CallWithNullParameterTest.java b/src/test/java/com/ql/util/express/test/CallWithNullParameterTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..7e47f1e5f8bd06512caf320b7285005f31d30e96
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/CallWithNullParameterTest.java
@@ -0,0 +1,21 @@
+package com.ql.util.express.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.ql.util.express.DefaultContext;
+import com.ql.util.express.ExpressRunner;
+
+public class CallWithNullParameterTest {
+
+ @Test
+ public void testABC() throws Exception {
+ String express = "new com.ql.util.express.test.BeanExample().testLongObject(null);";
+ ExpressRunner runner = new ExpressRunner();
+ DefaultContext context = new DefaultContext();
+ Object r = runner.execute(express, context, null, false,
+ true);
+ System.out.println(r);
+ Assert.assertTrue("数组操作实现错误", r.toString().equalsIgnoreCase("toString-LongObject:null"));
+ }
+}
diff --git a/src/test/java/com/ql/util/express/test/DefineTest.java b/src/test/java/com/ql/util/express/test/DefineTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..243965af7b1c79648d85aa2319cb1e74dd0e77c7
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/DefineTest.java
@@ -0,0 +1,130 @@
+package com.ql.util.express.test;
+
+import java.util.HashMap;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.ql.util.express.DefaultContext;
+import com.ql.util.express.ExpressRunner;
+import com.ql.util.express.InstructionSet;
+
+public class DefineTest {
+ @org.junit.Test
+ public void testDefExpressInner() throws Exception{
+ String express = "int qh = 1 ";
+ DefaultContext context = new DefaultContext();
+ ExpressRunner runner = new ExpressRunner(false,true);
+ context.put("qh",100);
+ Object r = runner.execute(express,context, null, false,false);
+ Assert.assertTrue("表达式变量作用域错误", r.toString().equalsIgnoreCase("1"));
+ Assert.assertTrue("表达式变量作用域错误", context.get("qh").toString().equalsIgnoreCase("100"));
+ }
+
+ @org.junit.Test
+ public void testDefUserContext() throws Exception{
+ String express = "qh = 1 + 1";
+ DefaultContext context = new DefaultContext();
+ ExpressRunner runner = new ExpressRunner();
+ context.put("qh",100);
+ Object r = runner.execute(express,context, null, false,false);
+ Assert.assertTrue("表达式变量作用域错误", r.toString().equalsIgnoreCase("2"));
+ Assert.assertTrue("表达式变量作用域错误", context.get("qh").toString().equalsIgnoreCase("2"));
+ }
+ @org.junit.Test
+ public void testAlias() throws Exception {
+ String express = " 定义别名 qh example.child; "
+ + "{定义别名 qh example.child.a;" + " qh =qh + \"-ssss\";" + "};"
+ + " qh.a = qh.a +\"-qh\";" + " return example.child.a";
+ ExpressRunner runner = new ExpressRunner();
+ runner.addOperatorWithAlias("定义别名", "alias", null);
+ DefaultContext context = new DefaultContext();
+ context.put("example", new BeanExample());
+ runner.addOperatorWithAlias("如果", "if", null);
+ runner.addOperatorWithAlias("则", "then", null);
+ runner.addOperatorWithAlias("否则", "else", null);
+ Object r = runner.execute(express,context, null, false,false);
+ Assert.assertTrue("别名实现 错误", r.toString().equalsIgnoreCase("qh-ssss-qh"));
+ Assert.assertTrue("别名实现 错误", ((BeanExample) context.get("example")).child.a.toString().equalsIgnoreCase("qh-ssss-qh"));
+ }
+ @org.junit.Test
+ public void testMacro() throws Exception{
+ String express ="定义宏 惩罚 {bean.unionName(name)}; 惩罚; return 惩罚";
+ ExpressRunner runner = new ExpressRunner();
+ runner.addOperatorWithAlias("定义宏", "macro", null);
+ DefaultContext context = new DefaultContext();
+ context.put("bean", new BeanExample("qhlhl2010@gmail.com"));
+ context.put("name","xuannn");
+ Object r = runner.execute(express,context, null, false,false);
+ Assert.assertTrue("别名宏 错误", r.toString().equalsIgnoreCase("qhlhl2010@gmail.com-xuannn"));
+ System.out.println(r);
+ }
+ @Test
+ public void test_自定义函数() throws Exception{
+ String express ="定义函数 递归(int a){" +
+ " if(a == 1)then{ " +
+ " return 1;" +
+ " }else{ " +
+ " return 递归(a - 1) * a;" +
+ " } " +
+ "}; " +
+ "递归(10);";
+ ExpressRunner runner = new ExpressRunner();
+ runner.addOperatorWithAlias("定义函数", "function",null);
+ DefaultContext context = new DefaultContext();
+ Object r = runner.execute(express,context, null, true,false);
+ Assert.assertTrue("自定义函数 错误", r.toString().equals("3628800"));
+ }
+ @org.junit.Test
+ public void testProperty() throws Exception{
+ //String express =" cache isVIP(\"qh\") ; cache isVIP(\"xuannan\") cache isVIP(\"qh\") ;";
+
+ String express =" example.child.a = \"ssssssss\";" +
+ " map.name =\"ffff\";" +
+ "return map.name;";
+ ExpressRunner runner = new ExpressRunner();
+ DefaultContext context = new DefaultContext();
+ context.put("example", new BeanExample("张三"));
+ context.put("map",new HashMap());
+ runner.addFunctionOfClassMethod("isVIP", BeanExample.class.getName(),
+ "isVIP", new String[] { "String" }, "$1不是VIP用户");
+ Object r = runner.execute(express,context, null, false,false);
+ Assert.assertTrue("属性操作错误", r.toString().equalsIgnoreCase("ffff"));
+ Assert.assertTrue("属性操作错误", ((BeanExample)context.get("example")).child.a.toString().equalsIgnoreCase("ssssssss"));
+ }
+
+ @org.junit.Test
+ public void test_循环() throws Exception{
+ long s = System.currentTimeMillis();
+ String express ="qh = 0; 循环(int i = 1; i<=10;i = i + 1){ if(i > 5) then{ 终止;}; " +
+ "循环(int j=0;j<10;j= j+1){ " +
+ " if(j > 5)then{" +
+ " 终止;" +
+ " }; " +
+ " qh = qh + j;" +
+ //" 打印(i +\":\" + j+ \":\" +qh);"+
+ " }; " +
+ "};" +
+ "return qh;";
+ ExpressRunner runner = new ExpressRunner();
+ runner.addOperatorWithAlias("循环", "for",null);
+ runner.addOperatorWithAlias("继续", "continue",null);
+ runner.addOperatorWithAlias("终止", "break",null);
+ runner.addFunctionOfServiceMethod("打印", System.out, "println", new String[]{Object.class.getName()}, null);
+ DefaultContext context = new DefaultContext();
+ context.put("bean", new BeanExample("qhlhl2010@gmail.com"));
+ context.put("name","xuannn");
+ int count = 1;
+ s = System.currentTimeMillis();
+ Object r = runner.execute(express,context, null, false,false);
+
+ System.out.println("编译耗时:" + (System.currentTimeMillis() - s));
+
+ for(int i=0;i context = new DefaultContext();
+ runner.execute("sum=0;for(i=0;i<10;i=i+1){sum=sum+i;}", context, null,
+ true, true);
+ }
+
+ /**
+ * for嵌套循环
+ *
+ * @throws Exception
+ */
+ @org.junit.Test
+ public void testForLoop2() throws Exception {
+ ExpressRunner runner = new ExpressRunner(true, true);
+ DefaultContext context = new DefaultContext();
+ runner.execute(
+ "sum=0;for(i=0;i<10;i=i+1){for(j=0;j<10;j++){sum=sum+i+j;}}",
+ context, null, false, true);
+ }
+
+ /**
+ * 汉诺塔算法
+ *
+ * @throws Exception
+ */
+ @org.junit.Test
+ public void testHanoiMethod() throws Exception {
+ ExpressRunner runner = new ExpressRunner(false, false);
+ runner.addFunctionOfClassMethod("汉诺塔算法", DemoShow.class.getName(),
+ "hanoi", new Class[] { int.class, char.class, char.class,
+ char.class }, null);
+ runner.execute("汉诺塔算法(3, '1', '2', '3')", null, null, false, false);
+ }
+
+ /**
+ * 汉诺塔算法2
+ *
+ * @throws Exception
+ */
+ @org.junit.Test
+ public void testHanoiMethod2() throws Exception {
+ ExpressRunner runner = new ExpressRunner(false, false);
+ runner.addFunctionOfServiceMethod("汉诺塔算法", new DemoShow(), "hanoi",
+ new Class[] { int.class, char.class, char.class, char.class },
+ null);
+ runner.execute("汉诺塔算法(3, '1', '2', '3')", null, null, false, false);
+ }
+
+ /**
+ * 汉诺塔算法3
+ *
+ * @throws Exception
+ */
+ @org.junit.Test
+ public void testHanoiMethod3() throws Exception {
+ ExpressRunner runner = new ExpressRunner(false, true);
+ runner.addFunctionOfServiceMethod("汉诺塔算法", new DemoShow(), "hanoi",
+ new Class[] { int.class, char.class, char.class, char.class },
+ null);
+ runner.addMacro("汉诺塔算法演示", "汉诺塔算法(3, '1', '2', '3')");
+ runner.execute("汉诺塔算法演示", null, null, false, false);
+ }
+ // 将n个盘从one座借助two座,移到three座
+ public void hanoi(int n, char one, char two, char three) {
+ if (n == 1)
+ move(one, three);
+ else {
+ hanoi(n - 1, one, three, two);
+ move(one, three);
+ hanoi(n - 1, two, one, three);
+ }
+ }
+ private void move(char x, char y) {
+ System.out.println(x + "--->" + y);
+ }
+
+ /**
+ * 自定义操作符
+ *
+ * @throws Exception
+ */
+ @org.junit.Test
+ public void testOperator() throws Exception {
+ ExpressRunner runner = new ExpressRunner(false, false);
+ DefaultContext context = new DefaultContext();
+ runner.addOperator("join",new JoinOperator());
+ Object r = runner.execute("1 join 2 join 3", context, null, false, false);
+ System.out.println(r);
+ }
+ @SuppressWarnings({ "unchecked", "rawtypes","serial" })
+ public class JoinOperator extends Operator{
+ public Object executeInner(Object[] list) throws Exception {
+ Object opdata1 = list[0];
+ Object opdata2 = list[1];
+ if(opdata1 instanceof java.util.List){
+ ((java.util.List)opdata1).add(opdata2);
+ return opdata1;
+ }else{
+ java.util.List result = new java.util.ArrayList();
+ result.add(opdata1);
+ result.add(opdata2);
+ return result;
+ }
+ }
+ }
+
+ /**
+ * 替换操作符
+ *
+ * @throws Exception
+ */
+ @org.junit.Test
+ public void testReplaceOperator() throws Exception {
+ ExpressRunner runner = new ExpressRunner(false, false);
+ DefaultContext context = new DefaultContext();
+ Object r = runner.execute("1 + 2 + 3", context, null, false, false);
+ System.out.println(r);
+ runner.replaceOperator("+",new JoinOperator());
+ r = runner.execute("1 + 2 + 3", context, null, false, false);
+ System.out.println(r);
+ }
+
+ /**
+ * 替换操作符
+ *
+ * @throws Exception
+ */
+ @org.junit.Test
+ public void testShortLogicAndErrorInfo() throws Exception {
+ ExpressRunner runner = new ExpressRunner(false, false);
+ DefaultContext context = new DefaultContext();
+ context.put("A类违规天数90天内", true);
+ context.put("虚假交易扣分", 11);
+ context.put("假冒扣分", 11);
+ context.put("待整改卖家", false);
+ context.put("宝贝相符DSR", 4.0);
+ String expression =
+ "A类违规天数90天内 ==false and (虚假交易扣分<48 or 假冒扣分<12) and 待整改卖家 ==false and 宝贝相符DSR>4.6";
+ expression = initial(runner,expression);
+ List errorInfo = new ArrayList();
+ boolean result = (Boolean)runner.execute(expression, context, errorInfo, true, false);
+ if(result){
+ System.out.println("符合营销活动规则");
+ }else{
+ System.out.println("不符合营销活动规则");
+ for(String error : errorInfo){
+ System.out.println(error);
+ }
+ }
+ }
+ public String initial(ExpressRunner runner,String expression) throws Exception{
+ runner.setShortCircuit(false);
+ runner.addOperatorWithAlias("小于","<","$1 < $2 不符合");
+ runner.addOperatorWithAlias("大于",">","$1 > $2 不符合");
+ runner.addOperatorWithAlias("等于","==","$1 == $2 不符合");
+ return expression.replaceAll("<", " 小于 ").replaceAll(">", " 大于 ").replaceAll("==", " 等于 ");
+ }
+
+ /**
+ * 预加载表达式 & 虚拟类
+ * @throws Exception
+ */
+ @org.junit.Test
+ public void testVirtualClass() throws Exception {
+ ExpressRunner runner = new ExpressRunner(false, true);
+ runner.loadMutilExpress("类初始化", "class People(){sex;height;money;skin};");
+ runner.loadMutilExpress("创建小强", "a = new People();a.sex='male';a.height=185;a.money=10000000;");
+ runner.loadMutilExpress("体检", "if(a.sex=='male' && a.height>180 && a.money>5000000) return '高富帅,鉴定完毕'");
+ DefaultContext context = new DefaultContext();
+
+ Object r = runner.execute("类初始化;创建小强;体检", context, null, false, false);
+ System.out.println(r);
+ }
+
+
+}
diff --git a/src/test/java/com/ql/util/express/test/DongtaiFieldTest.java b/src/test/java/com/ql/util/express/test/DongtaiFieldTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..2d0708da808ba29946f857b4a5c14d1e9005056d
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/DongtaiFieldTest.java
@@ -0,0 +1,48 @@
+package com.ql.util.express.test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.ql.util.express.DefaultContext;
+import com.ql.util.express.ExpressRunner;
+import com.ql.util.express.InstructionSet;
+import com.ql.util.express.InstructionSetRunner;
+
+public class DongtaiFieldTest {
+
+ private static final Log log = LogFactory.getLog(DongtaiFieldTest.class);
+ @Test
+ public void testField() throws Exception{
+ String express ="String 用户 = \"张三\";" +
+ "费用.用户 = 100;" +
+ "用户 = \"李四\";" +
+ "费用.用户 = 200;";
+
+ ExpressRunner runner = new ExpressRunner(false,true);
+ DefaultContext context = new DefaultContext();
+ Map fee = new HashMap();
+ context.put("费用",fee);
+ InstructionSet set = runner.parseInstructionSet(express);
+ InstructionSetRunner.executeOuter(runner,set,null, context, null, true, false,null, true);
+ runner.execute(express, context, null, false, true);
+ System.out.println(context.get("费用"));
+ Assert.assertTrue("动态属性错误",fee.get("张三").toString().equals("100"));
+ Assert.assertTrue("动态属性错误",fee.get("李四").toString().equals("200"));
+ }
+ @Test
+ public void testLoadFromFile() throws Exception{
+ ExpressRunner runner = new ExpressRunner(true,true);
+ runner.loadExpress("TestFunctionParamerType");
+ DefaultContext context = new DefaultContext();
+ context.put("auctionUtil",new com.ql.util.express.test.BeanExample());
+ context.put("log",log);
+ Object r = runner.executeByExpressName("TestFunctionParamerType", context, null, false,false,null);
+ System.out.println(r );
+ System.out.println(context);
+ }
+}
diff --git a/src/test/java/com/ql/util/express/test/ExportDefine.java b/src/test/java/com/ql/util/express/test/ExportDefine.java
new file mode 100644
index 0000000000000000000000000000000000000000..025bf367bb9a2cb6554d283fb3708a7c0d6e1329
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/ExportDefine.java
@@ -0,0 +1,34 @@
+package com.ql.util.express.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.ql.util.express.DefaultContext;
+import com.ql.util.express.ExpressRunner;
+
+public class ExportDefine {
+
+ @Test
+ public void testABC() throws Exception {
+ String express =
+ "function initial(){" +
+ " exportAlias qh example.child ; exportDef int abc = 100;" +
+ "}; " +
+ "initial();" +
+ "abc = abc + 10000;" +
+ "System.out.println(abc);" +
+ "{" +
+ " alias qh example.child.a;"
+ + " qh =qh + \"-ssss\";"
+ + "};"
+ +" qh.a = qh.a +\"-qh\";" + " return example.child.a ";
+ ExpressRunner runner = new ExpressRunner(false,true);
+ DefaultContext context = new DefaultContext();
+ context.put("example", new BeanExample());
+ Object r = runner.execute(express, context, null, false, true);
+ System.out.println(r);
+ Assert.assertTrue("别名export实现 错误", r.toString().equalsIgnoreCase("qh-ssss-qh"));
+ Assert.assertTrue("别名export实现 错误", ((BeanExample) context.get("example")).child.a.toString().equalsIgnoreCase("qh-ssss-qh"));
+
+ }
+}
diff --git a/src/test/java/com/ql/util/express/test/ExpressCacheTest.java b/src/test/java/com/ql/util/express/test/ExpressCacheTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..015a7640553f4b3b81b70fd8cd89a01933927411
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/ExpressCacheTest.java
@@ -0,0 +1,95 @@
+package com.ql.util.express.test;
+
+import org.junit.Test;
+
+import com.ql.util.express.DefaultContext;
+import com.ql.util.express.ExpressRemoteCacheRunner;
+import com.ql.util.express.ExpressRunner;
+import com.ql.util.express.IExpressContext;
+import com.ql.util.express.LocalExpressCacheRunner;
+
+/**
+ * 关于ExpressRunner的脚本缓存管理方案
+ * @author tianqiao
+ *
+ */
+public class ExpressCacheTest {
+
+ ExpressRunner runner = new ExpressRunner();
+
+ @Test
+ public void testScriptCache() throws Exception {
+ runner.addMacro("计算平均成绩", "(语文+数学+英语)/3.0");
+ IExpressContext context =new DefaultContext();
+ context.put("语文", 88);
+ context.put("数学", 99);
+ context.put("英语", 95);
+ long times =10000;
+ long start = new java.util.Date().getTime();
+ while(times-->0){
+ calulateTask(false, context);
+ }
+ long end = new java.util.Date().getTime();
+ echo("不做缓存耗时:"+ (end-start) +" ms");
+
+ times =10000;
+ start = new java.util.Date().getTime();
+ while(times-->0){
+ calulateTask(true, context);
+ }
+ end = new java.util.Date().getTime();
+ echo("做缓存耗时:"+ (end-start) +" ms");
+
+ }
+
+ @Test
+ public void testLocalCacheMutualImpact()throws Exception {
+
+ //缓存在本地的脚本都是全局的,可以相互调用
+
+ runner.addMacro("计算平均成绩", "(语文+数学+英语)/3.0");
+ runner.addMacro("是否优秀", "计算平均成绩>90");
+ IExpressContext context =new DefaultContext();
+ context.put("语文", 88);
+ context.put("数学", 99);
+ context.put("英语", 95);
+ echo(runner.execute("是否优秀", context, null, false, false));
+ }
+
+ @Test
+ public void testRemoteCache(){
+ //数据的预先加载
+ ExpressRunner runner =new ExpressRunner();
+ ExpressRemoteCacheRunner cacheRunner = new LocalExpressCacheRunner(runner);
+ cacheRunner.loadCache("计算平均成绩", "(语文+数学+英语)/3.0");
+ cacheRunner.loadCache("是否优秀", "计算平均成绩>90");
+
+ IExpressContext context =new DefaultContext();
+ context.put("语文", 88);
+ context.put("数学", 99);
+ context.put("英语", 95);
+ //ExpressRemoteCacheRunner都只能执行自己原有的脚本内容,而且相互之间隔离,保证最高的脚本安全性
+ echo(cacheRunner.execute("计算平均成绩", context, null, false, false, null));
+ try{
+ echo(cacheRunner.execute("计算平均成绩>90", context, null, false, false, null));
+ }catch(Exception e){
+ echo("ExpressRemoteCacheRunner只支持预先加载的脚本内容");
+ }
+ try{
+ echo(cacheRunner.execute("是否优秀", context, null, false, false, null));
+ }catch(Exception e){
+ echo("ExpressRemoteCacheRunner不支持脚本间的相互调用");
+ }
+ }
+
+ private void echo(Object obj){
+ System.out.println(obj);
+ }
+
+ private void calulateTask(boolean isCache, IExpressContext context) throws Exception{
+ runner.execute("计算平均成绩", context, null, isCache, false);
+ }
+
+
+
+}
diff --git a/src/test/java/com/ql/util/express/test/ExpressContextExample.java b/src/test/java/com/ql/util/express/test/ExpressContextExample.java
new file mode 100644
index 0000000000000000000000000000000000000000..3da24c084eb22d01c90ad3bb3e9ec2bb49a2f852
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/ExpressContextExample.java
@@ -0,0 +1,53 @@
+package com.ql.util.express.test;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.springframework.context.ApplicationContext;
+
+import com.ql.util.express.IExpressContext;
+
+@SuppressWarnings("serial")
+public class ExpressContextExample extends HashMap implements IExpressContext{
+
+ private ApplicationContext context;
+
+ public ExpressContextExample(ApplicationContext aContext){
+ this.context = aContext;
+ }
+ public ExpressContextExample( Map aProperties,ApplicationContext aContext){
+ super(aProperties);
+ this.context = aContext;
+ }
+
+ /**
+ * 抽象方法:根据名称从属性列表中提取属性值
+ */
+ public Object get(Object name) {
+ Object result = null;
+ if(((String)name).equalsIgnoreCase("三星卖家")){
+ result = Boolean.valueOf(true);
+ } else if (((String)name).equalsIgnoreCase("消保用户")) {
+ result = Boolean.valueOf(true);
+ } else {
+ result = super.get(name);
+ }
+ try{
+ if (result == null &&this.context!= null && this.context.containsBean((String)name)) {
+ //如果在Spring容器中包含bean,则返回String的Bean
+ result = this.context.getBean((String)name);
+ }
+ }catch(Exception e){
+ throw new RuntimeException(e);
+ }
+ return result;
+ }
+
+ public Object put(String name, Object object) {
+ if(name.equalsIgnoreCase("myDbData")){
+ throw new RuntimeException("没有实现");
+ }
+ return super.put(name,object);
+ }
+
+
+}
diff --git a/src/test/java/com/ql/util/express/test/ExpressRemoteCacheTest.java b/src/test/java/com/ql/util/express/test/ExpressRemoteCacheTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..d9999a75279eee7028913ffdba81758b7fa1b313
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/ExpressRemoteCacheTest.java
@@ -0,0 +1,44 @@
+package com.ql.util.express.test;
+
+import org.junit.Assert;
+
+import com.ql.util.express.DefaultContext;
+import com.ql.util.express.ExpressRemoteCacheRunner;
+import com.ql.util.express.ExpressRunner;
+import com.ql.util.express.IExpressContext;
+import com.ql.util.express.LocalExpressCacheRunner;
+
+public class ExpressRemoteCacheTest {
+
+ @org.junit.Test
+ public void testcache(){
+ ExpressRunner runner =new ExpressRunner();
+ ExpressRemoteCacheRunner cacheRunner = new LocalExpressCacheRunner(runner);
+ cacheRunner.loadCache("加法计算", "a+b");
+ cacheRunner.loadCache("减法计算", "a-b");
+
+
+ IExpressContext context = new DefaultContext();
+ context.put("a", 1);
+ context.put("b", 2);
+
+ if(cacheRunner.getCache("加法计算")!=null){
+ Object result = cacheRunner.execute("加法计算", context, null, false, true, null);
+ Assert.assertTrue("加法计算", result.toString().equalsIgnoreCase("3"));
+ System.out.println(result);
+ }
+ if(cacheRunner.getCache("加法计算")!=null){
+ Object result = cacheRunner.execute("减法计算", context, null, false, true, null);
+ Assert.assertTrue("减法计算", result.toString().equalsIgnoreCase("-1"));
+ System.out.println(result);
+ }
+ if(cacheRunner.getCache("乘法计算")!=null){
+ Object result = cacheRunner.execute("乘法计算", context, null, false, true, null);
+ Assert.assertTrue("乘法计算", result.toString().equalsIgnoreCase("2"));
+ System.out.println(result);
+ }else{
+ System.out.println("没有定义乘法计算器.");
+ }
+ }
+
+}
diff --git a/src/test/java/com/ql/util/express/test/ExpressTest.java b/src/test/java/com/ql/util/express/test/ExpressTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..46474d0ec2bac4a7501a721d07e5a64c58a40e21
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/ExpressTest.java
@@ -0,0 +1,134 @@
+package com.ql.util.express.test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Assert;
+
+import com.ql.util.express.ExpressRunner;
+import com.ql.util.express.IExpressContext;
+
+public class ExpressTest {
+
+ @org.junit.Test
+ public void testDemo() throws Exception{
+ String express = "10 * 10 + 1 + 2 * 3 + 5 * 2";
+ ExpressRunner runner = new ExpressRunner();
+ Object r = runner.execute(express,null, null, false,false);
+ Assert.assertTrue("表达式计算", r.toString().equalsIgnoreCase("117"));
+ System.out.println("表达式计算:" + express + " = " + r);
+ }
+
+ @org.junit.Test
+ public void tes10000次() throws Exception{
+ ExpressRunner runner = new ExpressRunner();
+ String express = "10 * 10 + 1 + 2 * 3 + 5 * 2";
+ int num = 100000;
+ runner.execute(express,null, null, true,false);
+ long start = System.currentTimeMillis();
+ for(int i = 0;i< num;i++){
+ runner.execute(express,null, null, true,false);
+ }
+ System.out.println("执行" + num +"次\""+ express +"\" 耗时:"
+ + (System.currentTimeMillis() - start));
+ }
+
+ @org.junit.Test
+ public void testExpress() throws Exception{
+ ExpressRunner runner = new ExpressRunner();
+
+ runner.addOperatorWithAlias("如果", "if",null);
+ runner.addOperatorWithAlias("则", "then",null);
+ runner.addOperatorWithAlias("否则", "else",null);
+
+ runner.addOperator("love", new LoveOperator("love"));
+ runner.addOperatorWithAlias("属于", "in", "用户$1不在允许的范围");
+ runner.addOperatorWithAlias("myand", "and", "用户$1不在允许的范围");
+ runner.addFunction("累加", new GroupOperator("累加"));
+ runner.addFunction("group", new GroupOperator("group"));
+ runner.addFunctionOfClassMethod("isVIP", BeanExample.class.getName(),
+ "isVIP", new String[] { "String" }, "$1不是VIP用户");
+ runner.addFunctionOfClassMethod("取绝对值", Math.class.getName(), "abs",
+ new String[] { "double" }, null);
+ runner.addFunctionOfClassMethod("取绝对值TWO", Math.class.getName(), "abs",
+ new Class[] { double.class }, null);
+ runner.addFunctionOfClassMethod("转换为大写", BeanExample.class.getName(),
+ "upper", new String[] { "String" }, null);
+ runner.addFunctionOfClassMethod("testLong", BeanExample.class.getName(),
+ "testLong", new String[] { "long" }, null);
+ String[][] expressTest = new String[][] {
+ { "isVIP(\"qh\") ; isVIP(\"xuannan\"); return isVIP(\"qh\") ;", "false" },
+ { "如果 三星卖家 则 'a' love 'b' 否则 'b' love 'd' ", "b{a}b" },
+ { "when 三星卖家 then 'a' love 'b' 否则 'b' love 'd' ", "b{a}b" },
+ {"int defVar = 100; defVar = defVar + 100;", "200"},
+ {"int a=0; if false then a = 5 else a=10+1 ; return a ","11"},
+ { " 3+ (1==2?4:3) +8","14"},
+ { " 如果 (true) 则 {2+2;} 否则 {20 + 20;} ","4"},
+ {"'AAAAAAA' +'-' + \"\" +'' + \"B\"","AAAAAAA-B"},
+ { "System.out.println(\"ss\")", "null" },
+ {"unionName = new com.ql.util.express.test.BeanExample(\"张三\").unionName(\"李四\")",
+ "张三-李四" },
+ { "group(2,3,4)", "9" },
+ { "取绝对值(-5.0)", "5.0" },
+ { "取绝对值TWO(-10.0)", "10.0" },
+ { "max(2,3,4,10)", "10" },
+ {"max(2,-1)","2"},
+ { "max(3,2) + 转换为大写(\"abc\")", "3ABC" },
+ { "c = 1000 + 2000", "3000" },
+ { "b = 累加(1,2,3)+累加(4,5,6)", "21" },
+ { "三星卖家 and 消保用户 ", "true" },
+ { "new String(\"12345\").length()" ,"5"},
+ { "'a' love 'b' love 'c' love 'd'", "d{c{b{a}b}c}d" },
+ { "10 * (10 + 1) + 2 * (3 + 5) * 2", "142" },
+ { "( 2 属于 (4,3,5)) or isVIP(\"qhlhl2010@gmail.com\") or isVIP(\"qhlhl2010@gmail.com\")", "false" },
+ {" 1!=1 and isVIP(\"qhlhl2010@gmail.com\")","false"},
+ {" 1==1 or isVIP(\"qhlhl2010@gmail.com\") ","true"},
+ { "abc == 1", "true" },
+ { "2+2 in 2+2", "true" },
+ { "true or null", "true" },
+ { "null or true", "true" },
+ { "null or null", "false" },
+
+ { "true and null", "false" },
+ { "null and true", "false" },
+ { "null and null", "false" },
+
+ { "'a' nor null", "a" },
+ { "'a' nor 'b'", "a" },
+ { " null nor null", "null" },
+ { " null nor 'b'", "b" },
+
+ { "testLong(abc)", "toString-long:1" },
+ { "bean.testLongObject(abc)", "toString-LongObject:1" },
+
+ {"sum=0;n=7.3;for(i=0;i expressContext = new ExpressContextExample(null);
+ expressContext.put("b", new Integer(200));
+ expressContext.put("c", new Integer(300));
+ expressContext.put("d", new Integer(400));
+ expressContext.put("bean", new BeanExample());
+ expressContext.put("abc",1l);
+ expressContext.put("defVar",1000);
+
+
+ for (int point = 0; point < expressTest.length; point++) {
+ String expressStr = expressTest[point][0];
+ List errorList = new ArrayList();
+ Object result = runner.execute(expressStr,expressContext, null, false,true);
+ if (expressTest[point][1].equalsIgnoreCase("null")
+ && result != null
+ || result != null
+ && expressTest[point][1].equalsIgnoreCase(result
+ .toString()) == false) {
+ throw new Exception("处理错误,计算结果与预期的不匹配:" + expressStr + " = " + result + "但是期望值是:" + expressTest[point][1]);
+ }
+ System.out.println("Example " + point + " : " + expressStr + " = " + result);
+ if(errorList.size() > 0){
+ System.out.println("\t\t系统输出的错误提示信息:" + errorList);
+ }
+ }
+ System.out.println(expressContext);
+ }
+}
diff --git a/src/test/java/com/ql/util/express/test/ForFlowFunctionTest.java b/src/test/java/com/ql/util/express/test/ForFlowFunctionTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..4db96674c67df4f6179955cfabd0bc42158c6673
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/ForFlowFunctionTest.java
@@ -0,0 +1,24 @@
+package com.ql.util.express.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.ql.util.express.DefaultContext;
+import com.ql.util.express.ExpressRunner;
+
+
+public class ForFlowFunctionTest {
+
+ @Test
+ public void testABC() throws Exception {
+ String express = "for(i=0;i<1;i=i+1){" + "打印(70)"
+ + "}打印(70); return 10";
+ ExpressRunner runner = new ExpressRunner(false,true);
+ runner.addFunctionOfServiceMethod("打印", System.out, "println",
+ new String[] { "int" }, null);
+ DefaultContext context = new DefaultContext();
+ Object r = runner.execute(express, context, null, false, true);
+ Assert.assertTrue("for循环后面跟着一个函数的时候错误", r.toString().equals("10"));
+ }
+
+}
diff --git a/src/test/java/com/ql/util/express/test/FunctionDescTest.java b/src/test/java/com/ql/util/express/test/FunctionDescTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..b6fcad7cbc8ab67c8429e9e04a5a141013dfef3d
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/FunctionDescTest.java
@@ -0,0 +1,30 @@
+package com.ql.util.express.test;
+
+import com.ql.util.express.DefaultContext;
+import com.ql.util.express.ExpressRunner;
+import com.ql.util.express.instruction.op.OperatorBase;
+import com.ql.util.express.instruction.op.OperatorSelfDefineClassFunction;
+
+public class FunctionDescTest {
+ @org.junit.Test
+ public void testFunctionDesc() throws Exception{
+ String express ="isVIP(\"qianghui\")";
+ ExpressRunner runner = new ExpressRunner();
+ DefaultContext context = new DefaultContext();
+ runner.addFunctionOfClassMethod("isVIP", BeanExample.class.getName(),
+ "isVIP", new String[] { "String" },new String[]{"用户名称"},new String[]{"UserName"},"$1不是VIP用户");
+ OperatorBase op = runner.getFunciton("isVIP");
+ System.out.println(op.getOperDataDesc());
+ System.out.println(op.getOperDataAnnotaion());
+
+ Object r = runner.execute(express,context, null, false,false);
+ System.out.println(r);
+
+ runner.replaceOperator("isVIP", new OperatorSelfDefineClassFunction("isVIP",
+ BeanExample.class.getName(), "isVIPTwo", new String[] { "String" }, null,null,null));
+ Object r2 = runner.execute(express,context, null, false,false);
+ System.out.println(r2);
+// Assert.assertTrue("属性操作错误", r.toString().equalsIgnoreCase("ffff"));
+// Assert.assertTrue("属性操作错误", ((BeanExample)context.get("example")).child.a.toString().equalsIgnoreCase("ssssssss"));
+ }
+}
diff --git a/src/test/java/com/ql/util/express/test/GetExpressAttrNamesTest.java b/src/test/java/com/ql/util/express/test/GetExpressAttrNamesTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..b62bdd43b1601dc47889a03d6fd34567c0816b2f
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/GetExpressAttrNamesTest.java
@@ -0,0 +1,36 @@
+package com.ql.util.express.test;
+
+import com.ql.util.express.DefaultContext;
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.ql.util.express.ExpressRunner;
+
+public class GetExpressAttrNamesTest {
+
+ @Test
+ public void testABC() throws Exception {
+ String express = "alias qh 100; exportAlias fff qh; int a = b; c = a;macro 惩罚 {100 + 100} 惩罚; qh ;fff;";
+ ExpressRunner runner = new ExpressRunner(true,true);
+ String[] names = runner.getOutVarNames(express);
+ for(String s:names){
+ System.out.println("var : " + s);
+ }
+ Assert.assertTrue("获取外部属性错误",names.length == 2);
+ Assert.assertTrue("获取外部属性错误",names[0].equalsIgnoreCase("b"));
+ Assert.assertTrue("获取外部属性错误",names[1].equalsIgnoreCase("c"));
+ }
+
+ @Test
+ public void testABCD() throws Exception {
+ String express = "if(a!=null)return a";
+ ExpressRunner runner = new ExpressRunner(true,true);
+ String[] names = runner.getOutVarNames(express);
+ runner.execute(express,new DefaultContext(),null,false,false);
+ for(String s:names){
+ System.out.println("var : " + s);
+ }
+ Assert.assertTrue("获取外部属性错误",names.length == 1);
+ Assert.assertTrue("获取外部属性错误",names[0].equalsIgnoreCase("a"));
+ }
+}
diff --git a/src/test/java/com/ql/util/express/test/GetExpressFunctionNamesTest.java b/src/test/java/com/ql/util/express/test/GetExpressFunctionNamesTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..1b6780bad6f5a12d9107c29611f9efa75b17ab4e
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/GetExpressFunctionNamesTest.java
@@ -0,0 +1,71 @@
+package com.ql.util.express.test;
+
+import com.ql.util.express.DefaultContext;
+import com.ql.util.express.ExpressRunner;
+import com.ql.util.express.IExpressContext;
+import com.ql.util.express.Operator;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class GetExpressFunctionNamesTest {
+
+
+ public Object fun3(Object a,Object b)
+ {
+ return ""+a+b;
+ }
+
+ @Test
+ public void testFunctionDefine() throws Exception {
+ String express = "function fun1(){return null;} function fun2(int a,int b,int c){return a*b+c;} a =fun1();b=fun2(1,2,3)+fun3(1,2);";
+ ExpressRunner runner = new ExpressRunner(false,true);
+
+ String[] names = runner.getOutFunctionNames(express);
+ for(String s:names){
+ System.out.println("function : " + s);
+ }
+ Assert.assertTrue("获取外部方法错误",names.length == 1);
+ Assert.assertTrue("获取外部方法错误",names[0].equalsIgnoreCase("fun3"));
+
+ //注意:
+ // 如果已经通过function或者函数绑定定义了fun3, fun3就会变成一个普通的operator,这个接口就不会返回fun3函数定义
+
+ //(1)自定义function
+ runner = new ExpressRunner(true,true);
+ runner.addFunctionOfServiceMethod("fun3", this, "fun3", new Class[]{Object.class,Object.class}, null);
+
+ names = runner.getOutFunctionNames(express);
+ for(String s:names){
+ System.out.println("function : " + s);
+ }
+ Assert.assertTrue("获取外部方法错误",names.length == 0);
+
+ IExpressContext context = new DefaultContext();
+ Object r = runner.execute(express,context,null,false,false);
+ System.out.println("result : " + r);
+
+ //(2)函数绑定function
+ runner = new ExpressRunner(true,true);
+ runner.addFunction("fun3", new Operator() {
+ @Override
+ public Object executeInner(Object[] list) throws Exception {
+ String s = "";
+ for(Object obj : list){
+ s= s + obj;
+ }
+ return s;
+ }
+ });
+
+ names = runner.getOutFunctionNames(express);
+ for(String s:names){
+ System.out.println("function : " + s);
+ }
+ Assert.assertTrue("获取外部方法错误",names.length == 0);
+
+ context = new DefaultContext();
+ r = runner.execute(express,context,null,false,false);
+ System.out.println("result : " + r);
+
+ }
+}
diff --git a/src/test/java/com/ql/util/express/test/HTMLTest.java b/src/test/java/com/ql/util/express/test/HTMLTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..2729403dbd63d1377016f31a3f1be24121c358a3
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/HTMLTest.java
@@ -0,0 +1,19 @@
+package com.ql.util.express.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.ql.util.express.ExpressRunner;
+
+public class HTMLTest {
+ @Test
+ public void testABC() throws Exception {
+ //String express ="\"经费收入(\"";
+ ExpressRunner runner = new ExpressRunner(false,true);
+ String express ="\"经\\\"费收\\\"入\\\"aaa-\" + 100";
+ Object r = runner.execute(express, null, null, false, true);
+ System.out.println(r);
+ System.out.println("经\"费收\"入\"aaa-100");
+ Assert.assertTrue("字符串解析错误:",r.equals("经\"费收\"入\"aaa-100"));
+ }
+}
diff --git a/src/test/java/com/ql/util/express/test/IfTest.java b/src/test/java/com/ql/util/express/test/IfTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..9503427190acb8d414f0582b837b8e8d2401ef03
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/IfTest.java
@@ -0,0 +1,42 @@
+package com.ql.util.express.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.ql.util.express.DefaultContext;
+import com.ql.util.express.ExpressRunner;
+import com.ql.util.express.IExpressContext;
+
+public class IfTest {
+ @Test
+ public void testIf() throws Exception{
+ String[][] expresses = new String[][]{
+ {"if 1==1 then return 100 else return 10;","100"},
+ {"if 1==2 then return 100 else return 10;","10"},
+ {"if 1==1 then return 100; else return 10;","100"},
+ {"if 1==2 then return 100; else return 10;","10"},
+ {"if 1==1 then {return 100} else {return 10;}","100"},
+ {"if 1==2 then {return 100} else {return 10;}","10"},
+ {"if 1==1 then return 100 ; return 10000;","100"},
+ {"if 1==2 then return 100; return 10000;","10000"},
+ {"if (1==1) return 100 else return 10;","100"},
+ {"if (1==2) return 100 else return 10;","10"},
+ {"if (1==1) return 100; else return 10;","100"},
+ {"if (1==2) return 100; else return 10;","10"},
+ {"if (1==1) {return 100} else {return 10;}","100"},
+ {"if (1==2) {return 100} else {return 10;}","10"},
+ {"if (1==1) return 100 ; return 10000;","100"},
+ {"if (1==2) return 100; return 10000;","10000"},
+ };
+ for(int i=0;i expressContext = new DefaultContext();
+ ExpressRunner runner = new ExpressRunner(false,true);
+ runner.addOperatorWithAlias("加", "+",null);
+ runner.addOperator("love","+",new LoveOperator("love"));
+ Object result = runner.execute(expresses[i][0],expressContext, null, false,true);
+ System.out.println("运算结果:" + result);
+ System.out.println("环境结果:" + expressContext);
+ Assert.assertTrue("表达式执行错误:" + expresses[i][0] + " 期望值:" + expresses[i][1] +" 运算结果:" + result ,expresses[i][1].equals(result == null?"null":result.toString()));
+ }
+ }
+}
diff --git a/src/test/java/com/ql/util/express/test/ImportTest.java b/src/test/java/com/ql/util/express/test/ImportTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..edf60aa5bf7f70223c3f31be92cebf04454598bb
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/ImportTest.java
@@ -0,0 +1,23 @@
+package com.ql.util.express.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.ql.util.express.DefaultContext;
+import com.ql.util.express.ExpressRunner;
+
+public class ImportTest {
+ @Test
+ public void testImport() throws Exception{
+ String express ="import java.math.*;" +
+ "import com.ql.util.express.test.BeanExample;" +
+ "abc = new BeanExample(\"张三\").unionName(\"李四\") ;" +
+ "return new BigInteger(\"1000\");";
+ ExpressRunner runner = new ExpressRunner(false,true);
+ DefaultContext context = new DefaultContext();
+ Object r = runner.execute(express,context, null, false,true);
+ Assert.assertTrue("import 实现错误",r.toString().equals("1000"));
+ System.out.println(r);
+ System.out.println(context);
+ }
+}
diff --git a/src/test/java/com/ql/util/express/test/InTest.java b/src/test/java/com/ql/util/express/test/InTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..1279dcea6a0677fbb5ed2acc6332e7567a5045af
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/InTest.java
@@ -0,0 +1,32 @@
+package com.ql.util.express.test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+
+import com.ql.util.express.DefaultContext;
+import com.ql.util.express.ExpressRunner;
+
+public class InTest {
+ @Test
+ public void testOperaterIn() throws Exception {
+ String express1 = "2 in (2,3) ";
+ String express2 = "2 in a";
+ String express3 = "2 in b";
+
+ ExpressRunner runner = new ExpressRunner(true,true);
+ DefaultContext context = new DefaultContext();
+ int[] a = {1,2,3};
+ context.put("a", a);
+ List b = new ArrayList();
+ b.add(2);
+ b.add(3);
+
+ context.put("b", b);
+ System.out.println(runner.execute(express1, context, null, false,false));
+ System.out.println(runner.execute(express2, context, null, false,false));
+ System.out.println(runner.execute(express3, context, null, false,false));
+ }
+
+}
diff --git a/src/test/java/com/ql/util/express/test/IsAssignableTest.java b/src/test/java/com/ql/util/express/test/IsAssignableTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..df789411a2c6769185e6e8bd98f5c60b1f4995cf
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/IsAssignableTest.java
@@ -0,0 +1,45 @@
+package com.ql.util.express.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.ql.util.express.DefaultContext;
+import com.ql.util.express.ExpressRunner;
+import com.ql.util.express.ExpressUtil;
+
+public class IsAssignableTest {
+ @Test
+ public void testABC() throws Exception {
+ Assert.assertTrue("数据类型转换判断错误",ExpressUtil.isAssignable(boolean.class, Boolean.class) == true);
+ Assert.assertTrue("数据类型转换判断错误",ExpressUtil.isAssignable(char.class, java.lang.Character.class) == true);
+ Assert.assertTrue("数据类型转换判断错误",ExpressUtil.isAssignable(long.class, int.class) == true);
+ Assert.assertTrue("数据类型转换判断错误",ExpressUtil.isAssignable(Long.class, int.class) == true);
+ Assert.assertTrue("数据类型转换判断错误",ExpressUtil.isAssignable(Long.class, Integer.class) == true);
+ Assert.assertTrue("数据类型转换判断错误",ExpressUtil.isAssignable(java.util.List.class,java.util.AbstractList.class) == true);
+ Assert.assertTrue("数据类型转换判断错误",ExpressUtil.isAssignable(java.util.List.class,java.util.AbstractList.class) == ExpressUtil.isAssignableOld(java.util.List.class,java.util.AbstractList.class));
+ Assert.assertTrue("数据类型转换判断错误",ExpressUtil.isAssignable(long.class, int.class) == ExpressUtil.isAssignableOld(long.class, int.class));
+
+ int index = ExpressUtil.findMostSpecificSignature(new Class[]{Integer.class},
+ new Class[][]{{Integer.class},{int.class}});
+
+ System.out.println(index);
+
+ String express = "bean.testInt(p)";
+ ExpressRunner runner = new ExpressRunner(false,true);
+ DefaultContext context = new DefaultContext();
+ context.put("bean",new BeanExample());
+ context.put("p",100);
+
+ Object r = runner.execute(express, context, null, false, true);
+ System.out.println(r);
+ Assert.assertTrue("数据类型转换错误:",r.toString().equalsIgnoreCase("toString-int:100"));
+
+ context = new DefaultContext();
+ express = "bean.testLong(p)";
+ context.put("bean",new BeanExample());
+ context.put("p",100L);
+ r = runner.execute(express, context, null, false, true);
+ Assert.assertTrue("数据类型转换错误:",r.toString().equalsIgnoreCase("toString-long:100"));
+
+ }
+}
diff --git a/src/test/java/com/ql/util/express/test/LoadExpressFromFileTest.java b/src/test/java/com/ql/util/express/test/LoadExpressFromFileTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..101bf1d37059504d1465b15dcb1ab51d9a29f0ef
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/LoadExpressFromFileTest.java
@@ -0,0 +1,43 @@
+package com.ql.util.express.test;
+
+import org.apache.commons.logging.Log;
+import org.junit.Test;
+
+import com.ql.util.express.DefaultContext;
+import com.ql.util.express.ExportItem;
+import com.ql.util.express.ExpressRunner;
+
+public class LoadExpressFromFileTest {
+ @Test
+ public void testLoadFromFile() throws Exception {
+ ExpressRunner runner = new ExpressRunner(false,false);
+ runner.loadExpress("functiondef");
+ runner.loadExpress("main");
+ ExportItem[] exports = runner.getExportInfo();
+ for (ExportItem item : exports) {
+ System.out.println(item.getGlobeName());
+ }
+ DefaultContext context = new DefaultContext();
+ Log log = new MyLog("玄难测试");
+ Object r = runner.executeByExpressName("main", context, null,
+ false, false, log);
+ System.out.println("运行结果" + r);
+ System.out.println("context:" + context);
+
+ context = new DefaultContext();
+ r = runner.execute("initial;累加;累加;return qh;",
+ context, null, true, false, log);
+
+ System.out.println("运行结果" + r);
+ System.out.println("context:" + context);
+ }
+ @Test
+ public void testLoadInclude() throws Exception{
+ ExpressRunner runner = new ExpressRunner(false,true);
+ runner.loadExpress("includeRoot");
+ DefaultContext context = new DefaultContext();
+ Object r = runner.executeByExpressName("includeRoot", context, null, false,false,null);
+ System.out.println(r );
+ System.out.println(context);
+ }
+}
diff --git a/src/test/java/com/ql/util/express/test/LoveOperator.java b/src/test/java/com/ql/util/express/test/LoveOperator.java
new file mode 100644
index 0000000000000000000000000000000000000000..8148a58a13bd523089a551e4115810b2f1ba6f69
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/LoveOperator.java
@@ -0,0 +1,16 @@
+package com.ql.util.express.test;
+
+import com.ql.util.express.Operator;
+
+class LoveOperator extends Operator {
+ public LoveOperator(String aName) {
+ this.name= aName;
+ }
+ public Object executeInner(Object[] list)
+ throws Exception {
+ String op1 = list[0].toString();
+ String op2 = list[1].toString();
+ String result = op2 +"{" + op1 + "}" + op2;
+ return result;
+ }
+}
diff --git a/src/test/java/com/ql/util/express/test/MethodInvokeTest.java b/src/test/java/com/ql/util/express/test/MethodInvokeTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..0ae6e3c10e58517b2c955b3c8b525d6226352aaf
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/MethodInvokeTest.java
@@ -0,0 +1,158 @@
+package com.ql.util.express.test;
+
+import org.junit.Test;
+
+import com.ql.util.express.DefaultContext;
+import com.ql.util.express.ExpressRunner;
+import com.ql.util.express.IExpressContext;
+
+/**
+ * @author tianqiao
+ */
+public class MethodInvokeTest {
+
+
+ @Test
+ public void testNullParameter() throws Exception {
+ ExpressRunner runner = new ExpressRunner(false,false);
+
+ runner.addFunctionOfClassMethod("getSearchResult",
+ MethodInvokeTest.class.getName(),
+ "getSearchResult",
+ new Class[] {PersonalShopInfo.class},
+ null);
+
+ IExpressContext expressContext = new DefaultContext();
+ try{
+ Object r = runner.execute("getSearchResult(null)",
+ expressContext, null, false, false);
+ System.out.print("r=" + r);
+ }catch(Exception e){
+ e.printStackTrace();
+ throw new Exception(e);
+ }
+ }
+
+ @Test
+ public void testNullParameter2() throws Exception {
+ ExpressRunner runner = new ExpressRunner(false,false);
+
+ runner.addFunctionOfClassMethod("getOnlinePersonalShopInfo",
+ MethodInvokeTest.class.getName(),
+ "getOnlinePersonalShopInfo",
+ new Class[] {long.class},
+ null);
+
+ runner.addFunctionOfClassMethod("getSearchResult",
+ MethodInvokeTest.class.getName(),
+ "getSearchResult",
+ new Class[] {PersonalShopInfo.class},
+ null);
+
+ IExpressContext expressContext = new DefaultContext();
+ try{
+ Object r = runner.execute("getSearchResult(getOnlinePersonalShopInfo(123L))",
+ expressContext, null, false, false);
+ System.out.print("r=" + r);
+ }catch(Exception e){
+ e.printStackTrace();
+ throw new Exception(e);
+ }
+ }
+
+ @Test
+ public void testNullParameter3() throws Exception {
+ ExpressRunner runner = new ExpressRunner(false,true);
+
+ runner.addFunctionOfClassMethod("getOnlinePersonalShopInfo",
+ MethodInvokeTest.class.getName(),
+ "getOnlinePersonalShopInfo",
+ new Class[] {long.class},
+ null);
+ String express = "info = getOnlinePersonalShopInfo(127L);";
+
+ IExpressContext expressContext = new DefaultContext();
+ try{
+ Object r = runner.execute(express,
+ expressContext, null, false, false);
+ System.out.print("r=" + r);
+ }catch(Exception e){
+ e.printStackTrace();
+ throw new Exception(e);
+ }
+ }
+
+ @Test
+ public void testNullParameter4() throws Exception {
+ ExpressRunner runner = new ExpressRunner(false,true);
+
+ runner.addFunctionOfClassMethod("getOnlinePersonalShopInfo",
+ MethodInvokeTest.class.getName(),
+ "getOnlinePersonalShopInfo",
+ new Class[] {long.class},
+ null);
+ String express = "info = getOnlinePersonalShopInfo(127L);";
+
+ IExpressContext expressContext = new DefaultContext();
+ try{
+ Object r = runner.execute(express,
+ expressContext, null, false, false);
+ System.out.print("r=" + r);
+ }catch(Exception e){
+ e.printStackTrace();
+ throw new Exception(e);
+ }
+ }
+
+ @Test
+ public void testNullParameter5() throws Exception {
+ ExpressRunner runner = new ExpressRunner(false,true);
+
+ runner.addFunctionOfClassMethod("testVoidMethod",
+ MethodInvokeTest.class.getName(),
+ "testVoidMethod",
+ new Class[] {Long.class},
+ null);
+ String express = "info = testVoidMethod(1L);";
+
+ IExpressContext expressContext = new DefaultContext();
+ try{
+ Object r = runner.execute(express,
+ expressContext, null, false, false);
+ System.out.println("r=" + r);
+ }catch(Exception e){
+ e.printStackTrace();
+ System.out.println("return void checked success!");
+ return;
+ }
+ throw new Exception("return void exception not checked!");
+ }
+
+
+
+ //查找在线的店铺信息
+ public PersonalShopInfo getOnlinePersonalShopInfo(long userId) {
+ return null;
+// return new PersonalShopInfo();
+ }
+
+ //搜索引擎返回是否存在改店铺信息
+ public boolean getSearchResult(PersonalShopInfo personalInfo) {
+ if(personalInfo == null) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ public void testVoidMethod(Long id){
+ System.out.println("testVoidMethod");
+ }
+
+}
+
+class PersonalShopInfo {
+
+}
+
+
diff --git a/src/test/java/com/ql/util/express/test/MyLog.java b/src/test/java/com/ql/util/express/test/MyLog.java
new file mode 100644
index 0000000000000000000000000000000000000000..71190f2609ca14abd5c069951a5ca751133b4650
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/MyLog.java
@@ -0,0 +1,99 @@
+package com.ql.util.express.test;
+
+import org.apache.commons.logging.Log;
+
+public class MyLog implements Log{
+ String name ;
+ public MyLog(String aName){
+ this.name = aName;
+ }
+ public boolean isDebugEnabled() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean isErrorEnabled() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean isFatalEnabled() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean isInfoEnabled() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean isTraceEnabled() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean isWarnEnabled() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public void trace(Object message) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void trace(Object message, Throwable t) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void debug(Object message) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void debug(Object message, Throwable t) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void info(Object message) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void info(Object message, Throwable t) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void warn(Object message) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void warn(Object message, Throwable t) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void error(Object message) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void error(Object message, Throwable t) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void fatal(Object message) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void fatal(Object message, Throwable t) {
+ // TODO Auto-generated method stub
+
+ }
+ }
diff --git a/src/test/java/com/ql/util/express/test/NewExpressTest.java b/src/test/java/com/ql/util/express/test/NewExpressTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..3afedb7bed8d7c6b2e8d9dadc9284f73bef631a0
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/NewExpressTest.java
@@ -0,0 +1,85 @@
+package com.ql.util.express.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.ql.util.express.DefaultContext;
+import com.ql.util.express.ExpressRunner;
+import com.ql.util.express.IExpressContext;
+
+
+public class NewExpressTest {
+ @Test
+ public void testParse() throws Exception{
+ String[][] expresses = new String[][]{
+ {"0 - 3295837566L","-3295837566"},
+ {"1==1? 50+50:100+100","100"},
+ {"1==2? 50+50:100+100","200"},
+ {"int[][] abc = new int[10][10]; abc[0][0] = 100; abc[0][0]-10","90"},
+ {"Integer.parseInt(\"1\")-1","0"},
+ {"Double.parseDouble(\"-0.22\")","-0.22"},
+ {"(int)((Double.parseDouble(\"0.22\")-0.21)*100)","1"},
+ {"1+2+/** 注释测试 **/ 12+1 ","16"},
+ {"3240732988055L","3240732988055"},
+ {"3240732988054","3240732988054"},
+ {"0.5d","0.5"},
+ {"0.3f","0.3"},
+ {"0.55","0.55"},
+ {"1+1","2"},
+ {"(1+1)*(9-7);","4"},
+ {"1+1;2+5","7"},
+ {"false && true","false"},
+ {"true || fale","true"},
+ {"return 100/2;","50"},
+ {"return 10;1 + 1;","10"},
+ {"if(1==1) then{ return 100; }else{return 10;}","100"},
+ {"if(1==2) then{ return 100; }else{return 10;}","10"},
+ {"if(1==1) then{ return 100;}","100"},
+ {"if(1==2) then{ return 100;}","null"},
+ {"if(1==1) { return 100; }else{return 10;}","100"},
+ {"if(1==2) { return 100; }else{return 10;}","10"},
+ {"if(1==1) { return 100;}","100"},
+ {"if(1==2) { return 100;}","null"},
+ {"int i = 2","2"},
+ {"i=2;i<10;","true"},
+ {"a =0 ; for(int i=0;i<10;i=i+1){a = a + 1;} return a;","10"},
+ {"new String(\"ss\")","ss"},
+ {"(new String[1][1])[0][0]","null"},
+ {"a = new String[1][9]; a[0][1+1] = \"qianghui\"; b = a[0][2]; ","qianghui"},
+ {"(new String[3][5])[1].length","5"},
+ {"\"abc\".length()","3"},
+ {"\"abc\".substring(1,3).substring(1,2)","c"},
+ {"Integer.SIZE","32"},
+ {"new com.ql.util.express.test.BeanExample(\"qianghui\").name","qianghui"},
+ {"System.out.println(1)","null"},
+ {"int a = 0;for(int i= 0;i<10;i++){ System.out.println(i); a= a+ i} return a;","45"},
+ {"int a = 0;for(int i= 0;i<10;i++){ if(i > 5) then{break;} a= a+ i;} return a;","15"},
+ {"int a = 0;for(int i= 0;i<10;i++){ if(i <=5) then{continue;} a= a+ i;} return a;","30"},
+ {"int a =0; alias pa a; pa++ ;return a","1"},
+ {"int[][] a = new int[10][10]; alias pa a[0]; pa[0] =100 ;return a[0][0]","100"},
+ {"int[][] a = new int[10][10]; {exportAlias pa a[0]; pa[0] =100} ;pa[1] =200; return a[0][0] + a[0][1];","300"},
+ {"int[][] a = new int[10][10]; {exportDef int i = 1; exportDef int j=1; a[i][j] =999} ; return a[i][j];","999"},
+ {"return ((float)9)/2","4.5"},
+ {"int a =9; return ((float)a)/2","4.5"},
+ {"float a =9; return a/2","4.5"},
+ {"macro 惩罚 {100 + 100} 惩罚;","200"},
+ {"function union(String a,String b){return a +'-'+ b;}; union(\"qiang\",\"hui\")","qiang-hui"},
+ {" 3+4 in (8+3,7,9)","true"},
+ {"\"ab\" like \"a%\"","true"},
+ {"int 中国 = 100; int 美国 = 200 ;return 中国 + 美国","300"},
+ {"1 加 1 ","2"},
+ {" 'a' love 'b' love 'c'","c{b{a}b}c"},
+ {"if 1==2 then {return 10}else{return 100}","100"}
+ };
+ for(int i=0;i expressContext = new DefaultContext();
+ ExpressRunner runner = new ExpressRunner(false,true);
+ runner.addOperatorWithAlias("加", "+",null);
+ runner.addOperator("love","+",new LoveOperator("love"));
+ Object result = runner.execute(expresses[i][0],expressContext, null, false,true);
+ System.out.println("运算结果:" + result);
+ System.out.println("环境结果:" + expressContext);
+ Assert.assertTrue("表达式执行错误:" + expresses[i][0] + " 期望值:" + expresses[i][1] +" 运算结果:" + result ,expresses[i][1].equals(result == null?"null":result.toString()));
+ }
+ }
+}
diff --git a/src/test/java/com/ql/util/express/test/NumberComputerTest.java b/src/test/java/com/ql/util/express/test/NumberComputerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..55a1f248bd38e65cef4e827c4e047c3b5c537a3b
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/NumberComputerTest.java
@@ -0,0 +1,69 @@
+package com.ql.util.express.test;
+
+import java.math.BigDecimal;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.ql.util.express.DefaultContext;
+import com.ql.util.express.ExpressRunner;
+
+public class NumberComputerTest {
+ public static void main(String args[]){
+ System.out.println(0.05+0.01);
+ System.out.println(1.0-0.42);
+ System.out.println(4.015*100);
+ System.out.println(123.3/100);
+ }
+ @Test
+ public void testBigDecimalComputer() throws Exception {
+ System.out.println(1.0-0.42); // 0.5800000000000001
+ String expressString = "1.0-0.42";
+ ExpressRunner runner = new ExpressRunner(true,false);
+ DefaultContext context = new DefaultContext();
+ Object r = runner.execute(expressString, context, null, false, false);
+ System.out.println(r); //0.58
+ Assert.assertTrue("精度计算错误",r.toString().equals("0.58"));
+ }
+ @Test
+ public void testBigDecimalTransfer() throws Exception {
+ String expressString = "System.out.println(new java.math.BigDecimal(0.02))";
+ ExpressRunner runner = new ExpressRunner(false,false);
+ BeanExample bean = new BeanExample();
+ DefaultContext context = new DefaultContext();
+ context.put("bean",bean);
+ Object r = runner.execute(expressString, context, null, false, false);
+ System.out.println(r);
+ }
+ @Test
+ public void testBigDecimal() throws Exception {
+ String expressString = "bean.intValue = 10;" +
+ "bean.longValue = 10000;" +
+ "bean.doubleValue = bean.intValue + 100.01;" +
+ "return bean.doubleValue + 10;";
+ ExpressRunner runner = new ExpressRunner(false,false);
+ BeanExample bean = new BeanExample();
+ DefaultContext context = new DefaultContext();
+ context.put("bean",bean);
+ Object r = runner.execute(expressString, context, null, false, false);
+ Assert.assertTrue("精度计算错误",r.getClass().equals(Double.class));
+
+ runner = new ExpressRunner(true,true);
+ bean = new BeanExample();
+ context = new DefaultContext();
+ context.put("bean",bean);
+ r = runner.execute(expressString, context, null, false, false);
+ Assert.assertTrue("精度计算错误",r.getClass().equals(BigDecimal.class));
+
+ }
+ @Test
+ public void testMod() throws Exception {
+ ExpressRunner runner = new ExpressRunner(false,true);
+ Assert.assertTrue("Mod计算错误", runner.execute("20 mod 5", null, null, true, true).toString()
+ .equalsIgnoreCase("0"));
+ Assert.assertTrue("Mod计算错误", runner.execute("20 mod 3", null, null, true, true).toString()
+ .equalsIgnoreCase("2"));
+ Assert.assertTrue("Mod计算错误", runner.execute("20 mod 1", null, null, true, true).toString()
+ .equalsIgnoreCase("0"));
+ }
+}
diff --git a/src/test/java/com/ql/util/express/test/ObjectBean.java b/src/test/java/com/ql/util/express/test/ObjectBean.java
new file mode 100644
index 0000000000000000000000000000000000000000..1a7b5a32ddada6e9474c6eb52435d4cb16ce3843
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/ObjectBean.java
@@ -0,0 +1,21 @@
+package com.ql.util.express.test;
+public class ObjectBean{
+ int amount;
+ int volume;
+ public ObjectBean(int aAmount,int aVolume){
+ this.amount =aAmount;
+ this.volume = aVolume;
+ }
+ public int getAmount() {
+ return amount;
+ }
+ public void setAmount(int amount) {
+ this.amount = amount;
+ }
+ public int getVolume() {
+ return volume;
+ }
+ public void setVolume(int volume) {
+ this.volume = volume;
+ }
+}
diff --git a/src/test/java/com/ql/util/express/test/ObjectTest.java b/src/test/java/com/ql/util/express/test/ObjectTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..b113d190785743662de37ee8933ddeae22e48f7d
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/ObjectTest.java
@@ -0,0 +1,23 @@
+package com.ql.util.express.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.ql.util.express.DefaultContext;
+import com.ql.util.express.ExpressRunner;
+
+public class ObjectTest {
+ @Test
+ public void testABC() throws Exception {
+ String express = "object.amount*2+object.volume";
+ ExpressRunner runner = new ExpressRunner();
+ DefaultContext context = new DefaultContext();
+ ObjectBean tempObject= new ObjectBean(100,60);
+ context.put("object", tempObject);
+ Object r = runner.execute(express, context, null, false,
+ true);
+ System.out.println(r);
+ Assert.assertTrue("数据执行错误", r.toString().equals(260) == false);
+ }
+
+}
diff --git a/src/test/java/com/ql/util/express/test/OpCallTest.java b/src/test/java/com/ql/util/express/test/OpCallTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..9c077e47efc7c5d8cfe97653d7474b0e0c6046f8
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/OpCallTest.java
@@ -0,0 +1,55 @@
+package com.ql.util.express.test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+
+import com.ql.util.express.ExpressRunner;
+import com.ql.util.express.IExpressContext;
+
+public class OpCallTest {
+ @Test
+ public void testList() throws Exception {
+ ExpressRunner runner = new ExpressRunner(false, true);
+ runner.addOperator("@love", new LoveOperator("@love"));
+ runner.loadMutilExpress(null, "function abc(String s){println(s)}");
+ runner.addOperatorWithAlias("打印","println",null);
+ runner.addFunctionOfClassMethod("isVIP", BeanExample.class.getName(),
+ "isVIP", new Class[]{String.class},"");
+ runner.addOperatorWithAlias("是否VIP","isVIP","亲爱的$1,你还不是VIP用户");
+
+ String[][] expressTest = new String[][] {
+ {"println \"ssssss\"","null"},
+ {"println (\"ssssss\")","null"},
+ {"abc (\"bbbbbbbb\")","null"},
+ {"打印 (\"函数别名测试\")","null"},
+ {"isVIP (\"玄难\")","false"},
+ {"是否VIP (\"玄难\")","false"},
+ };
+ IExpressContext expressContext = new ExpressContextExample(
+ null);
+
+ for (int point = 0; point < expressTest.length; point++) {
+ String expressStr = expressTest[point][0];
+ List errorList = new ArrayList();
+ Object result = runner.execute(expressStr, expressContext, errorList,
+ false, true);
+ if (result == null
+ && expressTest[point][1].equalsIgnoreCase("null") == false
+ || expressTest[point][1].equalsIgnoreCase("null")
+ && result != null
+ || result != null
+ && expressTest[point][1]
+ .equalsIgnoreCase(result.toString()) == false) {
+ throw new Exception("处理错误,计算结果与预期的不匹配:" + expressStr + " = "
+ + result + "但是期望值是:" + expressTest[point][1]);
+ }
+ System.out.println("Example " + point + " : " + expressStr + " = "
+ + result);
+ if (errorList.size() > 0) {
+ System.out.println("\t\t系统输出的错误提示信息:" + errorList);
+ }
+ }
+ }
+}
diff --git a/src/test/java/com/ql/util/express/test/OperatorExample.java b/src/test/java/com/ql/util/express/test/OperatorExample.java
new file mode 100644
index 0000000000000000000000000000000000000000..41f29b1025e7f5625a764b25b15f6e323c934e1a
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/OperatorExample.java
@@ -0,0 +1,19 @@
+package com.ql.util.express.test;
+
+import com.ql.util.express.Operator;
+import com.ql.util.express.OperatorOfNumber;
+
+
+class GroupOperator extends Operator {
+ public GroupOperator(String aName) {
+ this.name= aName;
+ }
+ public Object executeInner(Object[] list)throws Exception {
+ Object result = Integer.valueOf(0);
+ for (int i = 0; i < list.length; i++) {
+ result = OperatorOfNumber.add(result, list[i],false);
+ }
+ return result;
+ }
+}
+
diff --git a/src/test/java/com/ql/util/express/test/ReplaceOperatorTest.java b/src/test/java/com/ql/util/express/test/ReplaceOperatorTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..88b59b401ce4d90818556b80b4dfc2fb1872ca33
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/ReplaceOperatorTest.java
@@ -0,0 +1,65 @@
+package com.ql.util.express.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.ql.util.express.ExpressRunner;
+import com.ql.util.express.Operator;
+
+public class ReplaceOperatorTest {
+ @Test
+ public void testReplaceOperatorTest() throws Exception {
+ String express = " 3 + 4";
+ ExpressRunner runner = new ExpressRunner();
+ Object r = runner.execute(express, null, null,false, false);
+ System.out.println(r);
+ Assert.assertTrue("表达式计算", r.toString().equalsIgnoreCase("7"));
+ runner.replaceOperator("+", new ReplaceOperatorAddReduce("+"));
+ r = runner.execute(express, null, null,false, false);
+ System.out.println(r);
+ runner.replaceOperator("+", new ReplaceOperatorAddReduce2("+"));
+ r = runner.execute(express, null, null,false, false);
+ System.out.println(r);
+ runner.replaceOperator("+", new ReplaceOperatorAddReduce("+"));
+ r = runner.execute(express, null, null,false, false);
+ System.out.println(r);
+ Assert.assertTrue("替换操作符号错误", r.toString().equalsIgnoreCase("(3*4)"));
+ }
+}
+class ReplaceOperatorAddReduce extends Operator {
+ public ReplaceOperatorAddReduce(String name) {
+ this.name = name;
+ }
+ public ReplaceOperatorAddReduce(String aAliasName, String aName, String aErrorInfo) {
+ this.name = aName;
+ this.aliasName = aAliasName;
+ this.errorInfo = aErrorInfo;
+ }
+ public Object executeInner(Object[] list) throws Exception {
+ return executeInner(list[0], list[1]);
+ }
+
+ public Object executeInner(Object op1,
+ Object op2) throws Exception {
+ return "(" + op1 + "*" + op2 +")";
+ }
+}
+
+class ReplaceOperatorAddReduce2 extends Operator {
+ public ReplaceOperatorAddReduce2(String name) {
+ this.name = name;
+ }
+ public ReplaceOperatorAddReduce2(String aAliasName, String aName, String aErrorInfo) {
+ this.name = aName;
+ this.aliasName = aAliasName;
+ this.errorInfo = aErrorInfo;
+ }
+ public Object executeInner(Object[] list) throws Exception {
+ return executeInner(list[0], list[1]);
+ }
+
+ public Object executeInner(Object op1,
+ Object op2) throws Exception {
+ return "(" + op1 + "****" + op2 +")";
+ }
+}
diff --git a/src/test/java/com/ql/util/express/test/RunExample.java b/src/test/java/com/ql/util/express/test/RunExample.java
new file mode 100644
index 0000000000000000000000000000000000000000..5e3f63116758a332f160db2b8f4f55caaaaf2485
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/RunExample.java
@@ -0,0 +1,228 @@
+package com.ql.util.express.test;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+
+import com.ql.util.express.ExpressRunner;
+import com.ql.util.express.IExpressContext;
+import com.ql.util.express.Operator;
+import com.ql.util.express.instruction.OperateDataCacheManager;
+
+public class RunExample implements ApplicationContextAware, Runnable {
+ private ApplicationContext applicationContext;
+ ExpressRunner runner;
+ String[][] expressTest1 = new String[][]{
+ { "( 2 属于 (4,3,5)) or isVIP(\"qhlhl2010@gmail.com\") or isVIP(\"qhlhl2010@gmail.com\")", "false" },
+ };
+ String[][] expressTest = new String[][] {
+ { "isVIP(\"qh\") ; isVIP(\"xuannan\"); return isVIP(\"qh\") ;", "false" },
+ { "如果 三星卖家 则 'a' love 'b' 否则 'b' love 'd' ", "b{a}b" },
+ {"int defVar = 100; defVar = defVar + 100;", "200"},
+ {"int a=0; if false then a = 5 else a=10+1 ; return a ","11"},
+ { " 3+ (1==2?4:3) +8","14"},
+ { " 如果 (true) 则 {2+2;} 否则 {20 + 20;} ","4"},
+ {"'AAAAAAA' +'-' + \"\" +'' + \"B\"","AAAAAAA-B"},
+ //{ "System.out.println(\"ss\")", "null" },
+ {"unionName = new com.ql.util.express.test.BeanExample(\"张三\").unionName(\"李四\")",
+ "张三-李四" },
+ { "group(2,3,4)", "9" },
+ { "取绝对值(-5.0)", "5.0" },
+ { "取绝对值TWO(-10.0)", "10.0" },
+ { "max(2,3,4,10)", "10" },
+ {"max(2,-1)","2"},
+ { "max(3,2) + 转换为大写(\"abc\")", "3ABC" },
+ { "c = 1000 + 2000", "3000" },
+ { "b = 累加(1,2,3)+累加(4,5,6)", "21" },
+ { "三星卖家 and 消保用户 ", "true" },
+ { "new String(\"12345\").length()" ,"5"},
+ { "'a' love 'b' love 'c' love 'd'", "d{c{b{a}b}c}d" },
+ { "10 * (10 + 1) + 2 * (3 + 5) * 2", "142" },
+ { "( 2 属于 (4,3,5)) or isVIP(\"qhlhl2010@gmail.com\") or isVIP(\"qhlhl2010@gmail.com\")", "false" },
+ {" 1!=1 and isVIP(\"qhlhl2010@gmail.com\")","false"},
+ {" 1==1 or isVIP(\"qhlhl2010@gmail.com\") ","true"},
+ { "abc == 1", "true" },
+ { "2+2 in 2+2", "true" },
+ { "true or null", "true" },
+ { "null or true", "true" },
+ { "null or null", "false" },
+
+ { "true and null", "false" },
+ { "null and true", "false" },
+ { "null and null", "false" },
+
+ { "'a' nor null", "a" },
+ { "'a' nor 'b'", "a" },
+ { " null nor null", "null" },
+ { " null nor 'b'", "b" },
+
+ // { "testLong(abc)", "toString-long:1" },
+ { "bean.testLongObject(abc)", "toString-LongObject:1" },
+
+ {"sum=0;n=7.3;for(i=0;i expressContext = new ExpressContextExample(null);
+ expressContext.put("b", new Integer(200));
+ expressContext.put("c", new Integer(300));
+ expressContext.put("d", new Integer(400));
+ expressContext.put("bean", new BeanExample());
+ expressContext.put("abc",1l);
+ expressContext.put("defVar",1000);
+
+ }
+ public static void main(String[] args) throws Exception {
+ ExpressRunner runner = new ExpressRunner(false,true);
+ initialRunner(runner);
+ new RunExample(runner).run(1); //111
+ //new RunExample(runner).run(100000); // 8466
+
+ for (int i = 0; i < 5; i++) {
+ new Thread(new RunExample(runner)).start();
+ }
+// System.out.println(OperateDataCacheManager.getFetchCount());
+ }
+ public void run() {
+ run(1000000000);
+ }
+ public void run(int num) {
+ long start = System.currentTimeMillis();
+ try {
+ for (int j = 0; j < num; j++) {
+ IExpressContext expressContext = new ExpressContextExample( this.applicationContext);
+ expressContext.put("a", j);
+ expressContext.put("b", new Integer(200));
+ expressContext.put("c", new Integer(300));
+ expressContext.put("d", new Integer(400));
+ expressContext.put("bean", new BeanExample());
+ for (int point = 0; point < expressTest.length; point++) {
+ String s = expressTest[point][0];
+ // 批量处理的时候可以先预处理,会加快执行效率
+ //List errorList = new ArrayList();
+ // Object result = runner.parseInstructionSet(s);
+ runner.execute(s, expressContext, null, true, false);
+// if (expressTest[point][1].equalsIgnoreCase("null")
+// && result != null
+// || result != null
+// && expressTest[point][1].equalsIgnoreCase(result
+// .toString()) == false) {
+// throw new Exception("处理错误,计算结果与预期的不匹配");
+// }
+// System.out.println(s + " 执行结果 : " + result);
+// System.out.println("错误信息" + errorList);
+ }
+ // System.out.println(expressContext);
+
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ System.out.println(Thread.currentThread() + "耗时:"
+ + (System.currentTimeMillis() - start));
+ }
+
+ public void run2(int num) {
+ long start = System.currentTimeMillis();
+ try {
+ for (int j = 0; j < num; j++) {
+ String[][] expressTest = new String[][] {
+// { "System.out.println(\"ss\")", "null" },
+ {"unionName = new com.ql.util.express.test.BeanExample(\"张三\").unionName(\"李四\")",
+ "张三-李四" },
+ { "max(2,3,4,10)", "10" },
+ { " max(3,2) + 转换为大写(\"abc\")", "3ABC" },
+ { " null == null", "true" },
+ { " c = 1000 + 2000", "3000" },
+ { "b = 累加(1,2,3)+累加(4,5,6)", "21" },
+ { "三星卖家 and 消保用户 ", "true" },
+ { " ((1 + 1) 属于 (4,3,5)) and isVIP(\"qhlhl2010@gmail.com\")", "false" },
+ { "group(2,3,4)", "9" }, { "取绝对值(-5)", "5.0" },
+ { "2 属于(3,4)", "false" },
+ { "true myand false", "false" },
+ { "'a' love 'b' love 'c' love 'd'", "d{c{b{a}b}c}d" },
+ { " 10 * 10 + 1 + 2 * 3 + 5 * 2", "117" },
+ {" 1!=1 and 2==2 and 1 == 2","false"},
+ {" 80 > \"300\"","true"}
+ };
+ IExpressContext expressContext = new ExpressContextExample( this.applicationContext);
+ expressContext.put("a", j);
+ expressContext.put("b", new Integer(200));
+ expressContext.put("c", new Integer(300));
+ expressContext.put("d", new Integer(400));
+ expressContext.put("bean", new BeanExample());
+ for (int point = 0; point < expressTest.length; point++) {
+ String s = expressTest[point][0];
+ // 批量处理的时候可以先预处理,会加快执行效率
+ //List errorList = new ArrayList();
+ Object result = runner.execute(s,expressContext, null, false,false);
+ if (expressTest[point][1].equalsIgnoreCase("null")
+ && result != null
+ || result != null
+ && expressTest[point][1].equalsIgnoreCase(result
+ .toString()) == false) {
+ throw new Exception("处理错误,计算结果与预期的不匹配");
+ }
+// System.out.println(s + " 执行结果 : " + result);
+// System.out.println("错误信息" + errorList);
+ }
+ // System.out.println(expressContext);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ System.out.println(Thread.currentThread() + "耗时:"
+ + (System.currentTimeMillis() - start));
+ }
+
+}
+class EqualIn extends Operator{
+
+ @Override
+ public Object executeInner(Object[] list) throws Exception {
+ for (int i = 0 ; i < list.length ; i ++){
+ System.out.println(list[i]);
+ }
+ return Boolean.TRUE;
+ }
+
+}
+
diff --git a/src/test/java/com/ql/util/express/test/SkylightRuleTransferTest.java b/src/test/java/com/ql/util/express/test/SkylightRuleTransferTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..60e01795c7e4518e5a2e3c90ef4d2615ee4e0923
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/SkylightRuleTransferTest.java
@@ -0,0 +1,53 @@
+package com.ql.util.express.test;
+
+import org.junit.Test;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Created by tianqiao on 16/10/27.
+ */
+public class SkylightRuleTransferTest {
+
+ static Pattern pattern = Pattern.compile("[\\s]+");
+ static Pattern pattern2 = Pattern.compile("(rule|RULE)[\\s]+[\\S]+[\\s]+(name|NAME)[\\s]+[\\S]+[\\s]+");
+
+ public class Rule
+ {
+ public String name;
+ public String code;
+ public String content;
+ public String ql;
+
+ public Rule(String content) throws Exception {
+ this.content = content;
+ praseContent();
+ }
+
+ private void praseContent() throws Exception {
+ String[] strs = pattern.split(content);
+ if(strs.length>5 && (strs[0].equals("rule") || strs[0].equals("RULE")) && (strs[2].equals("name")||strs[2].equals("NAME"))){
+ this.code = strs[1];
+ this.name = strs[3];
+ Matcher matcher =pattern2.matcher(content);
+ this.ql = matcher.replaceFirst("");
+ }else{
+ System.out.println("规则定义不合法");
+ throw new Exception("规则定义不合法");
+ }
+ }
+
+ }
+
+
+ @Test
+ public void helloWorld() throws Exception {
+ String skylight = "rule test name 测试 for(i=0;i<10;i++){\nsum=sum+i;\n}\nreturn sum;\n";
+ Rule rule = new Rule(skylight);
+ System.out.println("code:"+rule.code);
+ System.out.println("name:"+rule.name);
+ System.out.println("ql脚本:\n"+rule.ql);
+
+ }
+}
diff --git a/src/test/java/com/ql/util/express/test/SpringConfig.xml b/src/test/java/com/ql/util/express/test/SpringConfig.xml
new file mode 100644
index 0000000000000000000000000000000000000000..55af999b1a1521ab973e074c1b71d3d388fc3bda
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/SpringConfig.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/src/test/java/com/ql/util/express/test/SubtractTest.java b/src/test/java/com/ql/util/express/test/SubtractTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..3f59489a214736b919316823c638df00984f45bc
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/SubtractTest.java
@@ -0,0 +1,20 @@
+package com.ql.util.express.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.ql.util.express.DefaultContext;
+import com.ql.util.express.ExpressRunner;
+
+public class SubtractTest {
+ @Test
+ public void testMax() throws Exception {
+ //String express = "return max(max(0.0,1) - 0.95,0);";
+ String express = "-3-(-5*-7-9)-(9-2);";
+ ExpressRunner runner = new ExpressRunner(false,true);
+ DefaultContext context = new DefaultContext();
+ Object r = runner.execute(express, context, null, false, true);
+ System.out.println(r);
+ Assert.assertTrue("\"-\"号测试",r.toString().equals("-36"));
+ }
+}
diff --git a/src/test/java/com/ql/util/express/test/TestAddMethodInvoke.java b/src/test/java/com/ql/util/express/test/TestAddMethodInvoke.java
new file mode 100644
index 0000000000000000000000000000000000000000..82af406d0afda877ca1a60a74dd184f3b3be9d41
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/TestAddMethodInvoke.java
@@ -0,0 +1,117 @@
+package com.ql.util.express.test;
+
+import com.ql.util.express.DefaultContext;
+import com.ql.util.express.ExpressRunner;
+import com.ql.util.express.IExpressContext;
+import com.ql.util.express.Operator;
+import org.apache.commons.lang.StringUtils;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by tianqiao on 16/10/17.
+ */
+public class TestAddMethodInvoke {
+ @Test
+ public void testStringMethod() throws Exception {
+ ExpressRunner runner = new ExpressRunner();
+ IExpressContext context = new DefaultContext();
+ Object result = runner.execute("'helloWorld'.length()",context,null,false,false);
+ System.out.println(result);
+
+ runner.addFunctionAndClassMethod("isBlank", Object.class, new Operator() {
+ @Override
+ public Object executeInner(Object[] list) throws Exception {
+ String str = (String) list[0];
+ return str.trim().length()==0;
+ }
+ });
+ runner.addFunctionAndClassMethod("isNotBlank", String.class, new Operator() {
+ @Override
+ public Object executeInner(Object[] list) throws Exception {
+ String str = (String) list[0];
+ return str.trim().length()>0;
+ }
+ });
+ result = runner.execute("isBlank('\t\n')",context,null,false,false);
+ assert ((Boolean) result);
+ result = runner.execute("'\t\n'.isBlank()",context,null,false,false);
+ assert ((Boolean) result);
+ result = runner.execute("isNotBlank('helloworld')",context,null,false,false);
+ assert ((Boolean) result);
+ result = runner.execute("'helloworld'.isNotBlank()",context,null,false,false);
+ assert ((Boolean) result);
+
+ }
+
+
+ @Test
+ public void testArrayOrMapJoinMethod() throws Exception {
+ ExpressRunner runner = new ExpressRunner();
+ IExpressContext context = new DefaultContext();
+
+ runner.addClassMethod("join", java.util.List.class, new Operator() {
+ @Override
+ public Object executeInner(Object[] list) throws Exception {
+ ArrayList arrayList = (ArrayList) list[0];
+ return StringUtils.join(arrayList,(String) list[1]);
+ }
+ });
+ runner.addClassMethod("join", java.util.Map.class, new Operator() {
+ @Override
+ public Object executeInner(Object[] list) throws Exception {
+ HashMap map = (HashMap) list[0];
+ StringBuilder sb = new StringBuilder();
+ for(Object key: map.keySet()){
+ sb.append(key).append("=").append(map.get(key)).append((String) list[1]);
+ }
+ return sb.substring(0,sb.length()-1);
+ }
+ });
+ Object result = runner.execute("list=new ArrayList();list.add(1);list.add(2);list.add(3);return list.join(' , ');",context,null,false,false);
+ System.out.println(result);
+ result = runner.execute("list=new HashMap();list.put('a',1);list.put('b',2);list.put('c',3);return list.join(' , ');",context,null,false,false);
+ System.out.println(result);
+
+
+ }
+
+
+ @Test
+ public void testAop() throws Exception {
+ ExpressRunner runner = new ExpressRunner();
+ IExpressContext context = new DefaultContext();
+
+ runner.addClassMethod("size", java.util.List.class, new Operator() {
+ @Override
+ public Object executeInner(Object[] list) throws Exception {
+ ArrayList arrayList = (ArrayList) list[0];
+ System.out.println("拦截到List.size()方法");
+ return arrayList.size();
+ }
+ });
+
+ runner.addClassField("长度", java.util.List.class, new Operator() {
+ @Override
+ public Object executeInner(Object[] list) throws Exception {
+ ArrayList arrayList = (ArrayList) list[0];
+ System.out.println("拦截到List.长度 字段的计算");
+ return arrayList.size();
+ }
+ });
+ Object result = runner.execute("list=new ArrayList();list.add(1);list.add(2);list.add(3);return list.size();",context,null,false,false);
+ System.out.println(result);
+ result = runner.execute("list=new ArrayList();list.add(1);list.add(2);list.add(3);return list.长度;",context,null,false,false);
+ System.out.println(result);
+
+ //bugfix 没有return 的时候可能会多次调用getType,并且返回错误
+ Object result2 = runner.execute("list=new ArrayList();list.add(1);list.add(2);list.add(3);list.长度;",context,null,false,false);
+ System.out.println(result2);
+
+
+ }
+}
diff --git a/src/test/java/com/ql/util/express/test/TestMap.java b/src/test/java/com/ql/util/express/test/TestMap.java
new file mode 100644
index 0000000000000000000000000000000000000000..c0f86863b0b0164f46d02c64a717301391059fb6
--- /dev/null
+++ b/src/test/java/com/ql/util/express/test/TestMap.java
@@ -0,0 +1,48 @@
+package com.ql.util.express.test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.ql.util.express.DefaultContext;
+import com.ql.util.express.ExpressRunner;
+import com.ql.util.express.IExpressContext;
+
+public class TestMap {
+
+ @Test
+ public void testInt2Object() throws Exception {
+ String express = "Map a = new HashMap(); a.put(\"a\",100 - 10);return a.get(\"a\")";
+ ExpressRunner runner = new ExpressRunner();
+ DefaultContext context = new DefaultContext();
+ Object r = runner.execute(express, context, null, false, true);
+ Assert.assertTrue("Map读取错误", r.toString().equalsIgnoreCase("90"));
+
+ }
+
+ @Test
+ public void testmain() throws Exception {
+ IExpressContext