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 + 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){ + ClasscomponentType = 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,ClassbindingClass, OperatorBase op) { + this.addFunction(name,op); + this.addClassMethod(name,bindingClass,op); + + }; + + /** + * 添加类的方法 + * @param field + * @param bindingClass + * @param op + */ + public void addClassField(String field,ClassbindingClass,Operator op) + { + this.addClassField(field,bindingClass,Object.class,op); + } + + /** + * 添加类的方法 + * @param field + * @param bindingClass + * @param returnType + * @param op + */ + public void addClassField(String field,ClassbindingClass,ClassreturnType,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,ClassbindingClass,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)bean).put(name, value); + } else { + Class filedClass = PropertyUtils.getPropertyType(bean, name.toString()); + PropertyUtils.setProperty(bean, name.toString(),ExpressUtil.castObject(value, filedClass, false)); + } + } catch (Exception e) { + throw new RuntimeException("不能访问" + bean + "的property:" + name,e); + } + } + + public static Object[] transferArray(Object[] values,Class[] types){ + for(int i=0;i type,boolean isForce){ + if (value == null) + return null; + if (value.getClass() == type || type.isAssignableFrom(value.getClass())) { + return value; + } + if (value instanceof Number + && (type.isPrimitive() || Number.class.isAssignableFrom(type))) { + return OperatorOfNumber.transfer((Number)value, type, isForce); + }else if(type.isArray() && value.getClass().isArray()) { + //需要对元素做兼容性,如果value的元素全部为null并且和声明的不一致,转化为所声明的类型 + Class valueType = value.getClass().getComponentType(); + Class declareType = type.getComponentType(); + if(declareType!=valueType){ + Object[] values = (Object[]) value; + boolean allBlank = true; + for(int i=0;i { +/** + * 根据名称从属性列表中提取属性值。如果表达式中用到了Spring的对象,也是通过此方法获取 + * @param name 属性名称 + * @return + * @throws Exception + */ + public V get(Object key); + /** + * 表达式计算的结果可以设置回调用系统,例如 userId = 3 + 4 + * @param name 属性名称 + * @param object 属性值 + * @throws Exception + */ + public V put(K name, V object); +} diff --git a/src/main/java/com/ql/util/express/IExpressResourceLoader.java b/src/main/java/com/ql/util/express/IExpressResourceLoader.java new file mode 100644 index 0000000000000000000000000000000000000000..0b53c00a452b91566cb2e048e6256fc96069b36c --- /dev/null +++ b/src/main/java/com/ql/util/express/IExpressResourceLoader.java @@ -0,0 +1,16 @@ +package com.ql.util.express; + +/** + * 加载表达式资源接口 + * @author xuannan + * + */ +public interface IExpressResourceLoader { + /** + * 根据表达式名称获取表达式的内容 + * @param expressName + * @return + * @throws Exception + */ + public String loadExpress(String expressName) throws Exception; +} diff --git a/src/main/java/com/ql/util/express/InstructionSet.java b/src/main/java/com/ql/util/express/InstructionSet.java new file mode 100644 index 0000000000000000000000000000000000000000..517231a1631202a83b3b63c42a47dabc38249805 --- /dev/null +++ b/src/main/java/com/ql/util/express/InstructionSet.java @@ -0,0 +1,315 @@ +package com.ql.util.express; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.concurrent.atomic.AtomicInteger; + +import com.ql.util.express.instruction.detail.*; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import com.ql.util.express.instruction.FunctionInstructionSet; +import com.ql.util.express.instruction.OperateDataCacheManager; +import com.ql.util.express.instruction.opdata.OperateDataLocalVar; + + + +/** + * 表达式执行编译后形成的指令集合 + * @author qhlhl2010@gmail.com + * + */ + +public class InstructionSet implements Serializable{ + + /** + * + */ + private static final long serialVersionUID = 1841743860792681669L; + + private static final transient Log log = LogFactory.getLog(InstructionSet.class); + public static AtomicInteger uniqIndex = new AtomicInteger(1); + public static String TYPE_MAIN ="main"; + public static String TYPE_CLASS ="VClass"; + public static String TYPE_FUNCTION ="function"; + public static String TYPE_MARCO ="marco"; + + public static boolean printInstructionError = true; + + + private String type ="main"; + private String name; + private String globeName; + + /** + * 指令 + */ + private Instruction[] instructionList = new Instruction[0]; + /** + * 函数和宏定义 + */ + private Map functionDefine = new HashMap(); + //为了增加性能,开始的时候缓存为数组 + private Map cacheFunctionSet = null; + private List exportVar = new ArrayList(); + /** + * 函数参数定义 + */ + private List parameterList = new ArrayList(); + + public static int getUniqClassIndex(){ + return uniqIndex.getAndIncrement(); + } + public InstructionSet(String aType){ + this.type = aType; + } + + public String[] getOutFunctionNames() throws Exception { + Map result = new TreeMap(); + for (int i = 0; i < instructionList.length; i++) { + Instruction instruction = instructionList[i]; + if (instruction instanceof InstructionCallSelfDefineFunction) { + String functionName = ((InstructionCallSelfDefineFunction)instruction).getFunctionName(); + if(!functionDefine.containsKey(functionName)) { + result.put(functionName, null); + } + } + } + return result.keySet().toArray(new String[0]); + + } + public String[] getOutAttrNames() throws Exception{ + Map result = new TreeMap(); + for(Instruction instruction:instructionList){ + if(instruction instanceof InstructionLoadAttr){ + if("null".equals(((InstructionLoadAttr)instruction).getAttrName())){ + continue; + } + result.put(((InstructionLoadAttr)instruction).getAttrName(),null); + } + } + + //剔除本地变量定义和别名定义 + for (int i = 0; i < instructionList.length; i++) { + Instruction instruction = instructionList[i]; + if (instruction instanceof InstructionOperator) { + String opName = ((InstructionOperator) instruction) + .getOperator().getName(); + if (opName.equalsIgnoreCase("def") + || opName.equalsIgnoreCase("exportDef")) { + String varLocalName = (String) ((InstructionConstData) instructionList[i - 1]) + .getOperateData().getObject(null); + result.remove(varLocalName); + } else if (opName.equalsIgnoreCase("alias") + || opName.equalsIgnoreCase("exportAlias")) { + String varLocalName = (String) ((InstructionConstData) instructionList[i - 2]) + .getOperateData().getObject(null); + result.remove(varLocalName); + } + } + } + return result.keySet().toArray(new String[0]); + } + + + /** + * 添加指令,为了提高运行期的效率,指令集用数组存储 + * @param item + * @return + */ + private void addArrayItem(Instruction item){ + Instruction[] newArray = new Instruction[this.instructionList.length + 1]; + System.arraycopy(this.instructionList, 0, newArray, 0, this.instructionList.length); + newArray[this.instructionList.length] = item; + this.instructionList = newArray; + } + /** + * 插入数据 + * @param aPoint + * @param item + */ + private void insertArrayItem(int aPoint,Instruction item){ + Instruction[] newArray = new Instruction[this.instructionList.length + 1]; + System.arraycopy(this.instructionList, 0, newArray, 0, aPoint); + System.arraycopy(this.instructionList, aPoint, newArray, aPoint + 1,this.instructionList.length - aPoint); + newArray[aPoint] = item; + this.instructionList = newArray; + } + +/** + * + * @param environmen + * @param context + * @param errorList + * @param isReturnLastData 是否最后的结果,主要是在执行宏定义的时候需要 + * @param aLog + * @return + * @throws Exception + */ + public CallResult excute(RunEnvironment environmen,InstructionSetContext context, + List errorList,boolean isReturnLastData,Log aLog) + throws Exception { + + //将函数export到上下文中,这儿就是重入也没有关系,不需要考虑并发 + if(cacheFunctionSet == null){ + Map tempMap = new HashMap(); + for(FunctionInstructionSet s : this.functionDefine.values()){ + tempMap.put(s.name,s.instructionSet); + } + cacheFunctionSet = tempMap; + } + + context.addSymbol(cacheFunctionSet); + + this.executeInnerOrigiInstruction(environmen, errorList, aLog); + if (environmen.isExit() == false) {// 是在执行完所有的指令后结束的代码 + if (environmen.getDataStackSize() > 0) { + OperateData tmpObject = environmen.pop(); + if (tmpObject == null) { + environmen.quitExpress(null); + } else { + if(isReturnLastData == true){ + if(tmpObject.getType(context) != null && tmpObject.getType(context).equals(void.class)){ + environmen.quitExpress(null); + }else{ + environmen.quitExpress(tmpObject.getObject(context)); + } + }else{ + environmen.quitExpress(tmpObject); + } + } + } + } + if (environmen.getDataStackSize() > 1) { + throw new Exception("在表达式执行完毕后,堆栈中还存在多个数据"); + } + CallResult result = OperateDataCacheManager.fetchCallResult(environmen.getReturnValue(), environmen.isExit()); + return result; + } + public void executeInnerOrigiInstruction(RunEnvironment environmen,List errorList,Log aLog) throws Exception{ + Instruction instruction =null; + try { + while (environmen.programPoint < this.instructionList.length) { +// if (environmen.isExit() == true) { +// return; +// } + instruction = this.instructionList[environmen.programPoint]; + instruction.setLog(aLog);// 设置log + instruction.execute(environmen, errorList); + } + } catch (Exception e) { + if (printInstructionError) { + log.error("当前ProgramPoint = " + environmen.programPoint); + log.error("当前指令" + instruction); + log.error(e); + } + throw e; + } + } + public int getInstructionLength(){ + return this.instructionList.length; + } + public void addMacroDefine(String macroName,FunctionInstructionSet iset){ + this.functionDefine.put(macroName, iset); + } + public FunctionInstructionSet getMacroDefine(String macroName){ + return this.functionDefine.get(macroName); + } + public FunctionInstructionSet[] getFunctionInstructionSets(){ + return this.functionDefine.values().toArray(new FunctionInstructionSet[0]); + } + public void addExportDef(ExportItem e){ + this.exportVar.add(e); + } + public List getExportDef(){ + List result = new ArrayList (); + result.addAll(this.exportVar); + return result; + } + + + public OperateDataLocalVar[] getParameters() { + return this.parameterList.toArray(new OperateDataLocalVar[0]); + } + + public void addParameter(OperateDataLocalVar localVar) { + this.parameterList.add(localVar); + } + public void addInstruction(Instruction instruction){ + this.addArrayItem(instruction); + } + public void insertInstruction(int point,Instruction instruction){ + this.insertArrayItem(point, instruction); + } + public Instruction getInstruction(int point){ + return this.instructionList[point]; + } + public int getCurrentPoint(){ + return this.instructionList.length - 1; + } + + public String getName() { + return name; +} + +public void setName(String name) { + this.name = name; +} + +public String getGlobeName() { + return globeName; +} + +public void setGlobeName(String globeName) { + this.globeName = globeName; +} +public boolean hasMain(){ + return this.instructionList.length >0; +} +public String getType() { + return type; +} +public void appendSpace(StringBuffer buffer,int level){ + for(int i=0;i 0){ + buffer.append(","); + } + buffer.append(var.getType(null).getName()).append(" ").append(var.getName()); + } + buffer.append("){\n"); + buffer.append(set.instructionSet.toString(level + 1)); + appendSpace(buffer,level); + buffer.append("}\n"); + } + for (int i = 0; i < this.instructionList.length; i++) { + appendSpace(buffer,level); + buffer.append(i + 1).append(":").append(this.instructionList[i]) + .append("\n"); + } + return buffer.toString(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} + + diff --git a/src/main/java/com/ql/util/express/InstructionSetContext.java b/src/main/java/com/ql/util/express/InstructionSetContext.java new file mode 100644 index 0000000000000000000000000000000000000000..4f80d5d8d396576cfc2e423f0573e135e77760ee --- /dev/null +++ b/src/main/java/com/ql/util/express/InstructionSetContext.java @@ -0,0 +1,136 @@ +package com.ql.util.express; + +import java.util.HashMap; +import java.util.Map; + +import com.ql.util.express.instruction.OperateDataCacheManager; + +public class InstructionSetContext implements IExpressContext { + /* + * 没有知道数据类型的变量定义是否传递到最外层的Context + */ + private boolean isExpandToParent = true; + + private IExpressContext parent = null; + private Map content; + /** + * 符号表 + */ + private Map symbolTable =new HashMap(); + + private ExpressLoader expressLoader; + + private boolean isSupportDynamicFieldName = false; + + public ExpressRunner getRunner() { + return runner; + } + + private ExpressRunner runner; + + public InstructionSetContext(boolean aIsExpandToParent,ExpressRunner aRunner,IExpressContext aParent,ExpressLoader aExpressLoader,boolean aIsSupportDynamicFieldName){ + this.initial(aIsExpandToParent, aRunner, aParent, aExpressLoader, aIsSupportDynamicFieldName); + } + public void initial(boolean aIsExpandToParent,ExpressRunner aRunner,IExpressContext aParent,ExpressLoader aExpressLoader,boolean aIsSupportDynamicFieldName){ + this.isExpandToParent = aIsExpandToParent; + this.runner = aRunner; + this.parent = aParent; + this.expressLoader = aExpressLoader; + this.isSupportDynamicFieldName = aIsSupportDynamicFieldName; + } + public void clear(){ + isExpandToParent = true; + parent = null; + content = null; + expressLoader = null; + isSupportDynamicFieldName = false; + runner = null; + symbolTable.clear(); + + } + public void exportSymbol(String varName,Object aliasNameObject) throws Exception{ + if( this.parent != null && this.parent instanceof InstructionSetContext){ + ((InstructionSetContext)this.parent).exportSymbol(varName, aliasNameObject); + }else{ + this.addSymbol(varName, aliasNameObject); + } + } + public void addSymbol(String varName,Object aliasNameObject) throws Exception{ + if(this.symbolTable.containsKey(varName)){ + throw new Exception("变量" + varName + "已经存在,不能重复定义,也不能再从函数内部 exprot "); + } + this.symbolTable.put(varName,aliasNameObject); + } + public void addSymbol(Map aliasNameObjects) throws Exception{ + this.symbolTable.putAll(aliasNameObjects); + } + + public void setSupportDynamicFieldName(boolean isSupportDynamicFieldName) { + this.isSupportDynamicFieldName = isSupportDynamicFieldName; + } + public boolean isSupportDynamicFieldName(){ + return this.isSupportDynamicFieldName; + } + public ExpressRunner getExpressRunner(){ + return this.runner; + } + public Object findAliasOrDefSymbol(String varName)throws Exception{ + Object result = this.symbolTable.get(varName); + if(result == null){ + if( this.parent != null && this.parent instanceof InstructionSetContext){ + result = ((InstructionSetContext)this.parent).findAliasOrDefSymbol(varName); + }else{ + result = null; + } + } + return result; + } + public Object getSymbol(String varName) throws Exception{ + Object result = this.symbolTable.get(varName); + if( result == null && this.expressLoader != null){ + result = this.expressLoader.getInstructionSet(varName); + } + if(result == null){ + if (this.isExpandToParent == true && this.parent != null + && this.parent instanceof InstructionSetContext) { + result = ((InstructionSetContext) this.parent) + .getSymbol(varName); + } else { + result = OperateDataCacheManager.fetchOperateDataAttr(varName, null); + this.addSymbol(varName, result); + } + } + return result; + } + + public ExpressLoader getExpressLoader() { + return expressLoader; + } + + public IExpressContext getParent(){ + return this.parent; + } + public Object get(Object key){ + if(this.content != null && this.content.containsKey(key)){ + return this.content.get(key); + }else if(this.isExpandToParent == true && this.parent != null){ + return this.parent.get(key); + } + return null; + } + public Object put(String key, Object value){ + if(this.content != null && this.content.containsKey(key) ){ + return this.content.put(key,value); + }else if (this.isExpandToParent == false){ + if(this.content == null){ + this.content = new HashMap(); + } + return this.content.put(key,value); + }else if(this.parent != null){ + return this.parent.put(key,value); + }else{ + throw new RuntimeException("没有定义局部变量:" + key +",而且没有全局上下文"); + } + } + +} diff --git a/src/main/java/com/ql/util/express/InstructionSetRunner.java b/src/main/java/com/ql/util/express/InstructionSetRunner.java new file mode 100644 index 0000000000000000000000000000000000000000..3de43bcdd09b49e1d6a9e29e054a6dc7e1dbc439 --- /dev/null +++ b/src/main/java/com/ql/util/express/InstructionSetRunner.java @@ -0,0 +1,78 @@ +package com.ql.util.express; + +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import com.ql.util.express.instruction.OperateDataCacheManager; + +public class InstructionSetRunner { + private static final Log log = LogFactory.getLog(InstructionSetRunner.class); + public static Object executeOuter(ExpressRunner runner,InstructionSet sets,ExpressLoader loader, + IExpressContext aContext, List errorList, + boolean isTrace,boolean isCatchException, + Log aLog,boolean isSupportDynamicFieldName) throws Exception{ + try{ + OperateDataCacheManager.push(runner); + return execute(runner,sets, loader, aContext, errorList, isTrace, isCatchException,true, aLog,isSupportDynamicFieldName); + }finally{ + OperateDataCacheManager.resetCache(runner); + } + } + + /** + * 批量执行指令集合,指令集间可以共享 变量和函数 + * @param runner + * @param sets + * @param loader + * @param aContext + * @param errorList + * @param isTrace + * @param isCatchException + * @param isReturnLastData + * @param aLog + * @param isSupportDynamicFieldName + * @return + * @throws Exception + */ + public static Object execute(ExpressRunner runner,InstructionSet sets,ExpressLoader loader, + IExpressContext aContext, List errorList, + boolean isTrace,boolean isCatchException, + boolean isReturnLastData,Log aLog,boolean isSupportDynamicFieldName) + throws Exception { + InstructionSetContext context = OperateDataCacheManager.fetchInstructionSetContext ( + true,runner,aContext,loader,isSupportDynamicFieldName); + Object result = execute(sets,context,errorList,isTrace,isCatchException,isReturnLastData,aLog); + return result; + } + + public static Object execute(InstructionSet set, + InstructionSetContext context, List errorList, boolean isTrace,boolean isCatchException, + boolean isReturnLastData,Log aLog) throws Exception { + + RunEnvironment environmen = null; + Object result = null; + environmen = OperateDataCacheManager.fetRunEnvironment(set, + (InstructionSetContext) context, isTrace); + try { + CallResult tempResult = set.excute(environmen, context, errorList, + isReturnLastData, aLog); + if (tempResult.isExit() == true) { + result = tempResult.getReturnValue(); + } + } catch (Exception e) { + if (isCatchException == true) { + if (aLog != null) { + aLog.error(e.getMessage(), e); + } else { + log.error(e.getMessage(), e); + } + } else { + throw e; + } + } + return result; + + } +} diff --git a/src/main/java/com/ql/util/express/LocalExpressCacheRunner.java b/src/main/java/com/ql/util/express/LocalExpressCacheRunner.java new file mode 100644 index 0000000000000000000000000000000000000000..fdbd03554c4176b14003e4aeced440d287babba1 --- /dev/null +++ b/src/main/java/com/ql/util/express/LocalExpressCacheRunner.java @@ -0,0 +1,35 @@ +package com.ql.util.express; + +import java.util.HashMap; +import java.util.Map; + +/** + * 作为表达式 + * @author tianqiao + * + */ +public class LocalExpressCacheRunner extends ExpressRemoteCacheRunner{ + + private static Map expressMap = new HashMap (); + + private ExpressRunner expressRunner; + + public LocalExpressCacheRunner(ExpressRunner expressRunner){ + this.expressRunner = expressRunner; + } + @Override + public final Object getCache(String key) { + return expressMap.get(key); + } + + @Override + public final void putCache(String key, Object object) { + expressMap.put(key, object); + } + + @Override + public final ExpressRunner getExpressRunner() { + return this.expressRunner; + } + +} diff --git a/src/main/java/com/ql/util/express/OperateData.java b/src/main/java/com/ql/util/express/OperateData.java new file mode 100644 index 0000000000000000000000000000000000000000..52d06953ab7c31fe4750d0a112655717bec5083b --- /dev/null +++ b/src/main/java/com/ql/util/express/OperateData.java @@ -0,0 +1,95 @@ +package com.ql.util.express; + + +/** + * 数据类型定义 + * @author qhlhl2010@gmail.com + * + */ + +public class OperateData implements java.io.Serializable { + private static final long serialVersionUID = 4749348640699065036L; + protected Object dataObject; + protected Class type; + + public OperateData(Object obj, Class aType) { + this.type = aType; + this.dataObject = obj; + } + /** + * 给对象缓存接口使用 + * @param obj + * @param aType + */ + public void initial(Object obj, Class aType) { + this.type = aType; + this.dataObject = obj; + } + public void clear(){ + this.dataObject = null; + this.type = null; + } + public Class getDefineType(){ + throw new RuntimeException(this.getClass().getName() + "必须实现方法:getDefineType"); + } + public Class getOrgiType(){ + return this.type; + } + public Class getType(InstructionSetContext parent) throws Exception { + if (type != null) + return type; + + Object obj = this.getObject(parent); + if (obj == null) + return null; + else + return obj.getClass(); + } + + public final Object getObject(InstructionSetContext context) throws Exception { + if(this.type != null && this.type.equals(void.class)){ + throw new Exception("void 不能参与任何操作运算,请检查使用在表达式中使用了没有返回值的函数,或者分支不完整的if语句"); + } + return getObjectInner(context); + } + public Object getObjectInner(InstructionSetContext context) throws Exception{ + return this.dataObject; + } + public void setObject(InstructionSetContext parent, Object object) throws Exception { + throw new RuntimeException("必须在子类中实现此方法"); + } + public String toJavaCode(){ + if(this.getClass().equals(OperateData.class) == false){ + throw new RuntimeException(this.getClass().getName() + "没有实现:toJavaCode()"); + } + String result ="new " + OperateData.class.getName() +"("; + if(String.class.equals(this.type)){ + result = result + "\"" + this.dataObject + "\""; + }else if(this.type.isPrimitive()){ + result = result + this.dataObject.getClass().getName() +".valueOf(\"" + this.dataObject + "\")"; + }else{ + result = result + "new " + this.dataObject.getClass().getName() + "(\"" + this.dataObject.toString() + "\")"; + } + result = result + "," + type.getName() + ".class"; + result = result + ")"; + return result; + } + public String toString() { + if( this.dataObject == null) + return this.type + ":null"; + else{ + if(this.dataObject instanceof Class){ + return ExpressUtil.getClassName((Class)this.dataObject); + }else{ + return this.dataObject.toString(); + } + } + } + public void toResource(StringBuilder builder,int level){ + if(this.dataObject != null){ + builder.append(this.dataObject.toString()); + }else{ + builder.append("null"); + } + } +} diff --git a/src/main/java/com/ql/util/express/Operator.java b/src/main/java/com/ql/util/express/Operator.java new file mode 100644 index 0000000000000000000000000000000000000000..a8187adc183ce282522c4000dcd0cd032779e74c --- /dev/null +++ b/src/main/java/com/ql/util/express/Operator.java @@ -0,0 +1,62 @@ +package com.ql.util.express; + +import com.ql.util.express.instruction.OperateDataCacheManager; +import com.ql.util.express.instruction.op.OperatorBase; + +/** + * 操作符的基类 + * @author xuannan + * + */ +public abstract class Operator extends OperatorBase{ + + public OperateData executeInner(InstructionSetContext context, ArraySwap list) throws Exception{ + Object[] parameters = new Object[list.length]; + for(int i = 0;i + * @throws Exception + */ + public static int compareData(Object op1,Object op2) throws Exception{ + int compareResult = -1; + + if(op1 instanceof String){ + compareResult = ((String)op1).compareTo(op2.toString()); + }else if(op2 instanceof String){ + compareResult = op1.toString().compareTo((String)op2); + }else if(op1 instanceof Number && op2 instanceof Number){ + //数字比较 + compareResult = OperatorOfNumber.compareNumber((Number)op1, (Number)op2); + } + else if ((op1 instanceof Boolean) && (op2 instanceof Boolean)) + { + if (((Boolean)op1).booleanValue() ==((Boolean)op2).booleanValue()) + compareResult =0; + else + compareResult =-1; + } + else + throw new Exception(op1 + "和" + op2 +"不能执行compare 操作"); + return compareResult; + } + +} diff --git a/src/main/java/com/ql/util/express/OperatorOfNumber.java b/src/main/java/com/ql/util/express/OperatorOfNumber.java new file mode 100644 index 0000000000000000000000000000000000000000..2b4c0675016c92ea78ec0e4791e8ea1b24fa333d --- /dev/null +++ b/src/main/java/com/ql/util/express/OperatorOfNumber.java @@ -0,0 +1,392 @@ +package com.ql.util.express; + +import java.math.BigDecimal; + +/** + * 数字运行函数集合 + * @author qhlhl2010@gmail.com + * + */ + +interface NumberType{ + public int NUMBER_TYPE_BYTE = 1; + public int NUMBER_TYPE_SHORT = 2; + public int NUMBER_TYPE_INT = 3; + public int NUMBER_TYPE_LONG = 4; + public int NUMBER_TYPE_FLOAT = 5; + public int NUMBER_TYPE_DOUBLE = 6; + public int NUMBER_TYPE_BIGDECIMAL = 7; +} + +public class OperatorOfNumber { + public static double round(double v, int scale) { + if (scale < 0) { + throw new IllegalArgumentException( + "The scale must be a positive integer or zero"); + } + BigDecimal b = new BigDecimal(Double.toString(v)); + BigDecimal one = new BigDecimal("1"); + return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).doubleValue(); + } + + /** + * 获取数据类型精度顺序 + * @param aClass + * @return + */ + public static int getSeq(Class aClass){ + if(aClass == Byte.class || aClass == byte.class) return NumberType.NUMBER_TYPE_BYTE; + if(aClass == Short.class || aClass == short.class) return NumberType.NUMBER_TYPE_SHORT; + if(aClass == Integer.class || aClass == int.class) return NumberType.NUMBER_TYPE_INT; + if(aClass == Long.class || aClass == long.class) return NumberType.NUMBER_TYPE_LONG; + if(aClass == Float.class || aClass == float.class) return NumberType.NUMBER_TYPE_FLOAT; + if(aClass == Double.class || aClass == double.class) return NumberType.NUMBER_TYPE_DOUBLE; + if(aClass == BigDecimal.class) return NumberType.NUMBER_TYPE_BIGDECIMAL; + throw new RuntimeException("不能处理的数据类型:" + aClass.getName()); + } + /** + * 进行数据类型转换 + * @param value + * @param type + * @return + */ + public static Number transfer(Number value,Class type,boolean isForce){ + if (isForce == true || value instanceof BigDecimal == false) { + if (type.equals(byte.class) || type.equals(Byte.class)) { + return ((Number) value).byteValue(); + } else if (type.equals(short.class) || type.equals(Short.class)) { + return ((Number) value).shortValue(); + } else if (type.equals(int.class) || type.equals(Integer.class)) { + return ((Number) value).intValue(); + } else if (type.equals(long.class) || type.equals(Long.class)) { + return ((Number) value).longValue(); + } else if (type.equals(float.class) || type.equals(Float.class)) { + return ((Number) value).floatValue(); + } else if (type.equals(double.class) + || type.equals(Double.class)) { + return ((Number) value).doubleValue(); + } else if (type.equals(BigDecimal.class)) { + return new BigDecimal(value.toString()); + }else{ + throw new RuntimeException("没有处理的数据类型:" + type.getName()); + } + } else { + if (type.equals(byte.class) || type.equals(Byte.class)) { + if(((BigDecimal)value).scale() >0 ){ + throw new RuntimeException("有小数位,不能转化为:"+ type.getName()); + } + return ((Number) value).byteValue(); + } else if (type.equals(short.class) || type.equals(Short.class)) { + if(((BigDecimal)value).scale() >0 ){ + throw new RuntimeException("有小数位,不能转化为:"+ type.getName()); + } + return ((Number) value).shortValue(); + } else if (type.equals(int.class) || type.equals(Integer.class)) { + if(((BigDecimal)value).scale() >0 ){ + throw new RuntimeException("有小数位,不能转化为:"+ type.getName()); + } + return ((Number) value).intValue(); + } else if (type.equals(long.class) || type.equals(Long.class)) { + if(((BigDecimal)value).scale() >0 ){ + throw new RuntimeException("有小数位,不能转化为:"+ type.getName()); + } + return ((Number) value).longValue(); + } else if (type.equals(float.class) || type.equals(Float.class)) { + return ((Number) value).floatValue(); + } else if (type.equals(double.class) + || type.equals(Double.class)) { + return ((Number) value).doubleValue(); + }else{ + throw new RuntimeException("没有处理的数据类型:" + type.getName()); + } + } + } + public static int compareNumber(Number op1, Number op2){ + int type1 = OperatorOfNumber.getSeq(op1.getClass()); + int type2 = OperatorOfNumber.getSeq(op2.getClass()); + int type = type1 > type2 ? type1:type2; + if(type == 1) { + byte o1 = ((Number)op1).byteValue(); + byte o2 = ((Number)op2).byteValue(); + if(o1 == o2) return 0; + if(o1 < o2) return -1; + return 1; + } + if(type == 2) { + short o1 = ((Number)op1).shortValue(); + short o2 = ((Number)op2).shortValue(); + if(o1 == o2) return 0; + if(o1 < o2) return -1; + return 1; + } + if(type == 3) { + int o1 = ((Number)op1).intValue(); + int o2 = ((Number)op2).intValue(); + if(o1 == o2) return 0; + if(o1 < o2) return -1; + return 1; + } + if(type == 4) { + long o1 = ((Number)op1).longValue(); + long o2 = ((Number)op2).longValue(); + if(o1 == o2) return 0; + if(o1 < o2) return -1; + return 1; + } + if(type == 5) { + float o1 = ((Number)op1).floatValue(); + float o2 = ((Number)op2).floatValue(); + if(o1 == o2) return 0; + if(o1 < o2) return -1; + return 1; + } + if(type == 6){ + double o1 = ((Number)op1).doubleValue(); + double o2 = ((Number)op2).doubleValue(); + if(o1 == o2) return 0; + if(o1 < o2) return -1; + return 1; + } + if(type == 7){ + BigDecimal o1 = new BigDecimal(op1.toString()); + BigDecimal o2 = new BigDecimal(op2.toString()); + return o1.compareTo(o2); + } + throw new RuntimeException("比较操作错误:op1=" + op1.toString() +",op2=" + op2.toString()); + + } + public static Object add(Object op1, Object op2,boolean isPrecise) throws Exception { + if(op1 == null){ + op1 = "null"; + } + if(op2 == null){ + op2 = "null"; + } + if (op1 instanceof String || op2 instanceof String) { + return op1.toString() + op2.toString(); + } + if(isPrecise==true){ + return PreciseNumberOperator.addPrecise((Number)op1,(Number)op2); + }else{ + return NormalNumberOperator.addNormal((Number)op1,(Number)op2); + } + } + public static Number subtract(Object op1, Object op2,boolean isPrecise) throws Exception { + if(isPrecise==true){ + return PreciseNumberOperator.subtractPrecise((Number)op1,(Number)op2); + }else{ + return NormalNumberOperator.subtractNormal((Number)op1,(Number)op2); + } + } + public static Number multiply(Object op1, Object op2,boolean isPrecise) throws Exception { + if(isPrecise==true){ + return PreciseNumberOperator.multiplyPrecise((Number)op1,(Number)op2); + }else{ + return NormalNumberOperator.multiplyNormal((Number)op1,(Number)op2); + } + } + public static Number divide(Object op1, Object op2,boolean isPrecise) throws Exception { + if(isPrecise==true){ + return PreciseNumberOperator.dividePrecise((Number)op1,(Number)op2); + }else{ + return NormalNumberOperator.divideNormal((Number)op1,(Number)op2); + } + } + public static Object modulo(Object op1,Object op2) throws Exception{ + return NormalNumberOperator.moduloNormal((Number)op1,(Number)op2); + } +} +class NormalNumberOperator { + + + /** + * 普通的加法运算 + * @param op1 + * @param op2 + * @return + * @throws Exception + */ + public static Number addNormal(Number op1, Number op2) throws Exception { + int type1 = OperatorOfNumber.getSeq(op1.getClass()); + int type2 = OperatorOfNumber.getSeq(op2.getClass()); + int type = type1 > type2 ? type1:type2; + if(type == NumberType.NUMBER_TYPE_BYTE) return op1.byteValue() + op2.byteValue(); + if(type == NumberType.NUMBER_TYPE_SHORT) return op1.shortValue() + op2.shortValue(); + if(type == NumberType.NUMBER_TYPE_INT) return op1.intValue() + op2.intValue(); + if(type == NumberType.NUMBER_TYPE_LONG) return op1.longValue() + op2.longValue(); + if(type == NumberType.NUMBER_TYPE_FLOAT) return op1.floatValue() + op2.floatValue(); + if(type == NumberType.NUMBER_TYPE_DOUBLE) return op1.doubleValue() + op2.doubleValue(); + if(type == NumberType.NUMBER_TYPE_BIGDECIMAL) return new BigDecimal(op1.toString()).add(new BigDecimal(op2.toString())); + throw new Exception("不支持的对象执行了\"+\"操作"); + } + + + + public static Number subtractNormal(Number op1,Number op2) throws Exception{ + int type1 = OperatorOfNumber.getSeq(op1.getClass()); + int type2 = OperatorOfNumber.getSeq(op2.getClass()); + int type = type1 > type2 ? type1:type2; + if(type == NumberType.NUMBER_TYPE_BYTE) return op1.byteValue() - op2.byteValue(); + if(type == NumberType.NUMBER_TYPE_SHORT) return op1.shortValue() - op2.shortValue(); + if(type == NumberType.NUMBER_TYPE_INT) return op1.intValue() - op2.intValue(); + if(type == NumberType.NUMBER_TYPE_LONG) return op1.longValue() - op2.longValue(); + if(type == NumberType.NUMBER_TYPE_FLOAT) return op1.floatValue() - op2.floatValue(); + if(type == NumberType.NUMBER_TYPE_DOUBLE) return op1.doubleValue() - op2.doubleValue(); + if(type == NumberType.NUMBER_TYPE_BIGDECIMAL) return new BigDecimal(op1.toString()).subtract(new BigDecimal(op2.toString())); + throw new Exception("不支持的对象执行了\"-\"操作"); + } + + public static Number multiplyNormal(Number op1,Number op2) throws Exception { + int type1 = OperatorOfNumber.getSeq(op1.getClass()); + int type2 = OperatorOfNumber.getSeq(op2.getClass()); + int type = type1 > type2 ? type1:type2; + if(type == NumberType.NUMBER_TYPE_BYTE) return op1.byteValue() * op2.byteValue(); + if(type == NumberType.NUMBER_TYPE_SHORT) return op1.shortValue() * op2.shortValue(); + if(type == NumberType.NUMBER_TYPE_INT) return op1.intValue() * op2.intValue(); + if(type == NumberType.NUMBER_TYPE_LONG) return op1.longValue() * op2.longValue(); + if(type == NumberType.NUMBER_TYPE_FLOAT) return op1.floatValue() * op2.floatValue(); + if(type == NumberType.NUMBER_TYPE_DOUBLE) return op1.doubleValue() * op2.doubleValue(); + if(type == NumberType.NUMBER_TYPE_BIGDECIMAL) return new BigDecimal(op1.toString()).multiply(new BigDecimal(op2.toString())); + throw new Exception("不支持的对象执行了\"*\"操作"); + } + public static Number divideNormal(Number op1,Number op2) throws Exception{ + int type1 = OperatorOfNumber.getSeq(op1.getClass()); + int type2 = OperatorOfNumber.getSeq(op2.getClass()); + int type = type1 > type2 ? type1:type2; + if(type == NumberType.NUMBER_TYPE_BYTE) return op1.byteValue() / op2.byteValue(); + if(type == NumberType.NUMBER_TYPE_SHORT) return op1.shortValue() / op2.shortValue(); + if(type == NumberType.NUMBER_TYPE_INT) return op1.intValue() / op2.intValue(); + if(type == NumberType.NUMBER_TYPE_LONG) return op1.longValue() / op2.longValue(); + if(type == NumberType.NUMBER_TYPE_FLOAT) return op1.floatValue() / op2.floatValue(); + if(type == NumberType.NUMBER_TYPE_DOUBLE) return op1.doubleValue() / op2.doubleValue(); + if(type == NumberType.NUMBER_TYPE_BIGDECIMAL) return new BigDecimal(op1.toString()).divide(new BigDecimal(op2.toString()), BigDecimal.ROUND_HALF_UP); + throw new Exception("不支持的对象执行了\"/\"操作"); + } + + + public static Number moduloNormal(Number op1,Number op2) throws Exception{ + int type1 = OperatorOfNumber.getSeq(op1.getClass()); + int type2 = OperatorOfNumber.getSeq(op2.getClass()); + int type = type1 > type2 ? type1:type2; + if(type == NumberType.NUMBER_TYPE_BYTE) return op1.byteValue() % op2.byteValue(); + if(type == NumberType.NUMBER_TYPE_SHORT) return op1.shortValue() % op2.shortValue(); + if(type == NumberType.NUMBER_TYPE_INT) return op1.intValue() % op2.intValue(); + if(type == NumberType.NUMBER_TYPE_LONG) return op1.longValue() % op2.longValue(); + throw new Exception("不支持的对象执行了\"mod\"操作"); + } +} + +/** + * 高精度计算 + * @author xuannan + */ +class PreciseNumberOperator { + + public static int DIVIDE_PRECISION = 10; + + public static Number addPrecise(Number op1, Number op2) throws Exception { + BigDecimal result = null; + if(op1 instanceof BigDecimal){ + if(op2 instanceof BigDecimal){ + result = ((BigDecimal)op1).add((BigDecimal)op2); + }else{ + result = ((BigDecimal)op1).add(new BigDecimal(op2.toString())); + } + }else{ + if(op2 instanceof BigDecimal){ + result = new BigDecimal(op1.toString()).add((BigDecimal)op2); + }else{ + result = new BigDecimal(op1.toString()).add(new BigDecimal(op2.toString())); + } + } + if(result.scale() ==0){ + long tempLong = result.longValue(); + if(tempLong <= Integer.MAX_VALUE && tempLong >= Integer.MIN_VALUE){ + return (int)tempLong; + }else{ + return tempLong; + } + }else{ + return result; + } + + } + public static Number subtractPrecise(Number op1, Number op2) throws Exception { + BigDecimal result = null; + if(op1 instanceof BigDecimal){ + if(op2 instanceof BigDecimal){ + result = ((BigDecimal)op1).subtract((BigDecimal)op2); + }else{ + result = ((BigDecimal)op1).subtract(new BigDecimal(op2.toString())); + } + }else{ + if(op2 instanceof BigDecimal){ + result = new BigDecimal(op1.toString()).subtract((BigDecimal)op2); + }else{ + result = new BigDecimal(op1.toString()).subtract(new BigDecimal(op2.toString())); + } + } + if(result.scale() ==0){ + long tempLong = result.longValue(); + if(tempLong <= Integer.MAX_VALUE && tempLong >= Integer.MIN_VALUE){ + return (int)tempLong; + }else{ + return tempLong; + } + }else{ + return result; + } + } + public static Number multiplyPrecise(Number op1, Number op2) throws Exception { + BigDecimal result = null; + if(op1 instanceof BigDecimal){ + if(op2 instanceof BigDecimal){ + result = ((BigDecimal)op1).multiply((BigDecimal)op2); + }else{ + result = ((BigDecimal)op1).multiply(new BigDecimal(op2.toString())); + } + }else{ + if(op2 instanceof BigDecimal){ + result = new BigDecimal(op1.toString()).multiply((BigDecimal)op2); + }else{ + result = new BigDecimal(op1.toString()).multiply(new BigDecimal(op2.toString())); + } + } + if(result.scale() ==0){ + long tempLong = result.longValue(); + if(tempLong <= Integer.MAX_VALUE && tempLong >= Integer.MIN_VALUE){ + return (int)tempLong; + }else{ + return tempLong; + } + }else{ + return result; + } + } + public static Number dividePrecise(Number op1, Number op2) throws Exception { + BigDecimal result = null; + if(op1 instanceof BigDecimal){ + if(op2 instanceof BigDecimal){ + result = ((BigDecimal)op1).divide((BigDecimal)op2, DIVIDE_PRECISION, BigDecimal.ROUND_HALF_UP); + }else{ + result = ((BigDecimal)op1).divide(new BigDecimal(op2.toString()), DIVIDE_PRECISION, BigDecimal.ROUND_HALF_UP); + } + }else{ + if(op2 instanceof BigDecimal){ + result = new BigDecimal(op1.toString()).divide((BigDecimal)op2, DIVIDE_PRECISION, BigDecimal.ROUND_HALF_UP); + }else{ + result = new BigDecimal(op1.toString()).divide(new BigDecimal(op2.toString()), DIVIDE_PRECISION, BigDecimal.ROUND_HALF_UP); + } + } + if(result.scale() ==0){ + long tempLong = result.longValue(); + if(tempLong <= Integer.MAX_VALUE && tempLong >= Integer.MIN_VALUE){ + return (int)tempLong; + }else{ + return tempLong; + } + }else{ + return result; + } + } +} diff --git a/src/main/java/com/ql/util/express/RunEnvironment.java b/src/main/java/com/ql/util/express/RunEnvironment.java new file mode 100644 index 0000000000000000000000000000000000000000..a2ead23e8a71f8f80b02c581411ff5f39ec632f7 --- /dev/null +++ b/src/main/java/com/ql/util/express/RunEnvironment.java @@ -0,0 +1,164 @@ +package com.ql.util.express; + + + +public final class RunEnvironment { + private static int INIT_DATA_LENTH = 15; + private boolean isTrace = false; + private int point = -1; + protected int programPoint = 0; + private OperateData[] dataContainer; + private ArraySwap arraySwap = new ArraySwap(); + + private boolean isExit = false; + private Object returnValue = null; + + private InstructionSet instructionSet; + private InstructionSetContext context; + + + public RunEnvironment(InstructionSet aInstructionSet,InstructionSetContext aContext,boolean aIsTrace){ + dataContainer = new OperateData[INIT_DATA_LENTH]; + this.instructionSet = aInstructionSet; + this.context = aContext; + this.isTrace = aIsTrace; + } + + public void initial(InstructionSet aInstructionSet,InstructionSetContext aContext,boolean aIsTrace){ + this.instructionSet = aInstructionSet; + this.context = aContext; + this.isTrace = aIsTrace; + } + public void clear(){ + isTrace = false; + point = -1; + programPoint = 0; + + isExit = false; + returnValue = null; + + instructionSet = null; + context = null; + + } + public InstructionSet getInstructionSet() { + return instructionSet; + } + + + public InstructionSetContext getContext(){ + return this.context; + } + public void setContext(InstructionSetContext aContext){ + this.context = aContext; + } + + public boolean isExit() { + return isExit; + } + public Object getReturnValue() { + return returnValue; + } + public void setReturnValue(Object value){ + this.returnValue = value; + } + public void quitExpress(Object aReturnValue){ + this.isExit = true; + this.returnValue = aReturnValue; + } + public void quitExpress(){ + this.isExit = true; + this.returnValue = null; + } + public boolean isTrace(){ + return this.isTrace; + } + public int getProgramPoint() { + return programPoint; + } + public void programPointAddOne() { + programPoint ++ ; + } + public void gotoLastWhenReturn(){ + programPoint = this.instructionSet.getInstructionLength(); + } + public int getDataStackSize(){ + return this.point + 1; + } + public void push(OperateData data){ + this.point++; + if(this.point >= this.dataContainer.length){ + ensureCapacity(this.point + 1); + } + this.dataContainer[point] = data; + } + public OperateData peek(){ + if(point <0){ + throw new RuntimeException("系统异常,堆栈指针错误"); + } + return this.dataContainer[point]; + } + public OperateData pop(){ + if(point <0) + throw new RuntimeException("系统异常,堆栈指针错误"); + OperateData result = this.dataContainer[point]; + this.point--; + return result; + } + public void clearDataStack(){ + this.point = -1; + } + public void gotoWithOffset(int aOffset ){ + this.programPoint = this.programPoint + aOffset; + } + /** + * 此方法是调用最频繁的,因此尽量精简代码,提高效率 + * @param context + * @param len + * @return + * @throws Exception + */ + public ArraySwap popArray(InstructionSetContext context,int len) throws Exception { + int start = point - len + 1; + this.arraySwap.swap(this.dataContainer,start,len); + point = point - len; + return this.arraySwap; + } + + public OperateData[] popArrayOld(InstructionSetContext context,int len) throws Exception { + int start = point - len + 1; + OperateData[] result = new OperateData[len]; + System.arraycopy(this.dataContainer,start, result,0, len); + point = point - len; + return result; + } + + public OperateData[] popArrayBackUp(InstructionSetContext context,int len) throws Exception { + int start = point - len + 1; + if(start <0){ + throw new Exception("堆栈溢出,请检查表达式是否错误"); + } + OperateData[] result = new OperateData[len]; + for (int i = 0 ; i < len; i++) { + result[i] = this.dataContainer[start + i]; + if(void.class.equals(result[i].getType(context))){ + throw new Exception("void 不能参与任何操作运算,请检查使用在表达式中使用了没有返回值的函数,或者分支不完整的if语句"); + } + } + point = point - len; + return result; + } + + public void ensureCapacity(int minCapacity) { + int oldCapacity = this.dataContainer.length; + if (minCapacity > oldCapacity) { + int newCapacity = (oldCapacity * 3) / 2 + 1; + if (newCapacity < minCapacity){ + newCapacity = minCapacity; + } + OperateData[] tempList = new OperateData[newCapacity]; + System.arraycopy(this.dataContainer,0,tempList,0,oldCapacity); + this.dataContainer = tempList; + } + } + } diff --git a/src/main/java/com/ql/util/express/console/Console.java b/src/main/java/com/ql/util/express/console/Console.java new file mode 100644 index 0000000000000000000000000000000000000000..85eae14886dc7777d8b507d58ceeaa637e87d7b6 --- /dev/null +++ b/src/main/java/com/ql/util/express/console/Console.java @@ -0,0 +1,53 @@ +package com.ql.util.express.console; + +import java.awt.Toolkit; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import java.awt.Dimension; + +public class Console { + boolean packFrame = false; + + /** + * Construct and show the application. + */ + public Console() { + ConsoleFrame frame = new ConsoleFrame(); + // Validate frames that have preset sizes + // Pack frames that have useful preferred size info, e.g. from their layout + if (packFrame) { + frame.pack(); + } + else { + frame.validate(); + } + + // Center the window + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + Dimension frameSize = frame.getSize(); + frameSize.height = screenSize.height; + frameSize.width = screenSize.width; + frame.setLocation(0,0); + frame.setVisible(true); + } + + /** + * Application entry point. + * + * @param args String[] + */ + public static void main(String[] args) { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } + catch (Exception exception) { + exception.printStackTrace(); + } + + new Console(); + } + }); + } +} diff --git a/src/main/java/com/ql/util/express/console/ConsoleFrame.java b/src/main/java/com/ql/util/express/console/ConsoleFrame.java new file mode 100644 index 0000000000000000000000000000000000000000..e70ff3ad07cbc063b02c1c00ac5c93ad09ba2b77 --- /dev/null +++ b/src/main/java/com/ql/util/express/console/ConsoleFrame.java @@ -0,0 +1,253 @@ +package com.ql.util.express.console; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseEvent; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Map; + +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JTabbedPane; +import javax.swing.JTextArea; +import javax.swing.JToolBar; +import javax.swing.tree.TreePath; + +import com.ql.util.express.DefaultContext; +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.console.FileTree.PathNode; + +public class ConsoleFrame + extends JFrame { + private static final long serialVersionUID = 1L; + JPanel contentPane; + BorderLayout borderLayout1 = new BorderLayout(); + JMenuBar jMenuBar1 = new JMenuBar(); + JMenu jMenuFile = new JMenu(); + JMenuItem jMenuFileExit = new JMenuItem(); + JToolBar jToolBar = new JToolBar(); + JButton jButton1 = new JButton(); + ImageIcon image1 = new ImageIcon(com.ql.util.express.console.ConsoleFrame.class. + getResource("run.png")); + JLabel statusBar = new JLabel(); + JTabbedPane jTabbedPaneContent = new JTabbedPane(); + JPanel jPaneRunner = new JPanel(); + JSplitPane jSplitPaneRun = new JSplitPane(); + BorderLayout borderLayout2 = new BorderLayout(); + JTextArea jTextAreaScript = new JTextArea(); + JScrollPane jScrollPaneScript = new JScrollPane(); + JSplitPane jSplitPaneS_C = new JSplitPane(); + JScrollPane jScrollPaneContext = new JScrollPane(); + JScrollPane jScrollPaneResult = new JScrollPane(); + JTextArea jTextAreaContext = new JTextArea(); + JTextArea jTextAreaResult = new JTextArea(); + JPanel jPanelResult = new JPanel(); + BorderLayout borderLayout3 = new BorderLayout(); + JLabel jLabelScript = new JLabel(); + JLabel jLabelResult = new JLabel(); + JLabel jLabelContext = new JLabel(); + JPanel jPanelScript = new JPanel(); + BorderLayout borderLayout4 = new BorderLayout(); + JPanel jPanelContext = new JPanel(); + BorderLayout borderLayout5 = new BorderLayout(); + StringBufferOutputStream output = new StringBufferOutputStream(jTextAreaResult); + public ConsoleFrame() { + try { + setDefaultCloseOperation(EXIT_ON_CLOSE); + jbInit(); + + PrintStream ps = new PrintStream(output,true); + System.setOut(ps); + } catch (Exception exception) { + exception.printStackTrace(); + } + } + + /** + * Component initialization. + * + * @throws java.lang.Exception + */ + private void jbInit() throws Exception { + contentPane = (JPanel) getContentPane(); + contentPane.setLayout(borderLayout1); + setSize(new Dimension(1000, 600)); + setTitle("QLExpressConsole"); + statusBar.setText(" "); + jMenuFile.setText("File"); + jMenuFileExit.setText("Exit"); + jMenuFileExit.addActionListener(new + ConsoleFrame_jMenuFileExit_ActionAdapter(this)); + jSplitPaneRun.setOrientation(JSplitPane.VERTICAL_SPLIT); + jSplitPaneRun.setDividerSize(2); + jPaneRunner.setLayout(borderLayout2); + jTextAreaScript.setText(""); + jTextAreaContext.setText(""); + jTextAreaResult.setText(""); + contentPane.setMinimumSize(new Dimension(500, 400)); + contentPane.setPreferredSize(new Dimension(500, 400)); + jButton1.addActionListener(new ConsoleFrame_jButton1_actionAdapter(this)); + jPanelResult.setLayout(borderLayout3); + jLabelScript.setText("运行脚本"); + jLabelResult.setText("运行结果"); + jLabelContext.setText("脚本上下文"); + jPanelScript.setLayout(borderLayout4); + jPanelContext.setLayout(borderLayout5); + jMenuBar1.add(jMenuFile); + jMenuFile.add(jMenuFileExit); + setJMenuBar(jMenuBar1); + jButton1.setIcon(image1); + jButton1.setToolTipText("执行"); + jToolBar.add(jButton1); + contentPane.add(statusBar, BorderLayout.SOUTH); + jPanelResult.add(jScrollPaneResult, java.awt.BorderLayout.CENTER); + jPanelResult.add(jLabelResult, java.awt.BorderLayout.NORTH); + jSplitPaneRun.add(jSplitPaneS_C, JSplitPane.TOP); + jScrollPaneResult.getViewport().add(jTextAreaResult); + + jPanelScript.add(jLabelScript, java.awt.BorderLayout.NORTH); + jPanelScript.add(jScrollPaneScript, java.awt.BorderLayout.CENTER); + jScrollPaneScript.getViewport().add(jTextAreaScript); + jPanelContext.add(jLabelContext, java.awt.BorderLayout.NORTH); + jPanelContext.add(jScrollPaneContext, java.awt.BorderLayout.CENTER); + jSplitPaneS_C.add(jPanelScript, JSplitPane.LEFT); + jScrollPaneContext.getViewport().add(jTextAreaContext); + jSplitPaneS_C.setDividerSize(2); + jSplitPaneS_C.setLastDividerLocation(200); + jSplitPaneS_C.add(jPanelContext, JSplitPane.RIGHT); + jSplitPaneS_C.setDividerLocation(500); + jSplitPaneRun.add(jPanelResult, JSplitPane.RIGHT); + jTabbedPaneContent.add(jPaneRunner, "\u6267\u884c\u4ee3\u7801"); + jPaneRunner.add(jSplitPaneRun, java.awt.BorderLayout.CENTER); + contentPane.add(jTabbedPaneContent, java.awt.BorderLayout.CENTER); + contentPane.add(jToolBar, java.awt.BorderLayout.NORTH); + jSplitPaneRun.setDividerLocation(200); + } + + /** + * File | Exit action performed. + * + * @param actionEvent ActionEvent + */ + void jMenuFileExit_actionPerformed(ActionEvent actionEvent) { + System.exit(0); + } + + public void jButton1_actionPerformed(ActionEvent e) { + String script =jTextAreaScript.getText(); + String[] lines = jTextAreaContext.getText().split("\n"); + String contextText =""; + for(int i =0;i< lines.length;i++){ + if(lines[i].trim().length() >0){ + String[] tempStr = lines[i].trim().split(":"); + if(contextText.length() >0){ + contextText = contextText +","; + } + contextText = contextText +"\"" + tempStr[0] +"\":" + tempStr[1]; + } + } + Object r = null; + try { + output.clear(); + ExpressRunner runner = new ExpressRunner(false,false); + contextText = "NewMap(" + contextText + ")"; + @SuppressWarnings("unchecked") + Map tempMap = (Map)runner.execute(contextText,null,null,false,false); + DefaultContext context = new DefaultContext(); + context.putAll(tempMap); + r = runner.execute(script, context, null,false,false); + System.out.print("QL>\n" + + "-------------------原始执行脚本--------------------------------\n" + + script + "\n" + + "-------------------脚本运行结果--------------------------------\n" + + r +"\n" + + "-------------------运行后上下文--------------------------------\n" + + context + + "\nQL>"); + } catch (Exception e1) { + e1.printStackTrace(System.out); + } + } + + public void jTreeFileSelect_mouseClicked(MouseEvent me) { + StringWriter writer = new StringWriter(); + try { + TreePath tp = ((FileTree)me.getSource()).getPathForLocation(me.getX(), me.getY()); + PathNode node = (PathNode)tp.getPath()[tp.getPathCount() -1]; + String fileName = node.getValue(); + ExampleDefine define = ReadExample.readExampleDefine(fileName); + jTextAreaScript.setText(define.getScript()); + jTextAreaContext.setText(define.getContext()); + } catch (Exception e) { + e.printStackTrace(new PrintWriter(writer)); + } + + } +} + +class ConsoleFrame_jButton1_actionAdapter + implements ActionListener { + private ConsoleFrame adaptee; + ConsoleFrame_jButton1_actionAdapter(ConsoleFrame adaptee) { + this.adaptee = adaptee; + } + + public void actionPerformed(ActionEvent e) { + try { + adaptee.jButton1_actionPerformed(e); + } catch (Exception e1) { + e1.printStackTrace(); + } + } +} + +class ConsoleFrame_jMenuFileExit_ActionAdapter + implements ActionListener { + ConsoleFrame adaptee; + + ConsoleFrame_jMenuFileExit_ActionAdapter(ConsoleFrame adaptee) { + this.adaptee = adaptee; + } + + public void actionPerformed(ActionEvent actionEvent) { + adaptee.jMenuFileExit_actionPerformed(actionEvent); + } +} + +class StringBufferOutputStream extends OutputStream +{ + protected ByteArrayOutputStream buffer; + JTextArea jTextArea; + public StringBufferOutputStream(JTextArea aJTextAreaResult) + { + jTextArea = aJTextAreaResult; + buffer = new ByteArrayOutputStream(); + } + public void clear(){ + this.buffer.reset(); + } + public void write(int ch) + throws IOException + { + this.buffer.write(ch); + + } + public void flush() throws IOException { + jTextArea.setText(this.buffer.toString()); + } +} diff --git a/src/main/java/com/ql/util/express/console/ConsoleFrame2.java b/src/main/java/com/ql/util/express/console/ConsoleFrame2.java new file mode 100644 index 0000000000000000000000000000000000000000..8e627aa53afa5d0cda088c928b04fcbd2bef0e33 --- /dev/null +++ b/src/main/java/com/ql/util/express/console/ConsoleFrame2.java @@ -0,0 +1,261 @@ +package com.ql.util.express.console; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Map; + +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JTabbedPane; +import javax.swing.JTextArea; +import javax.swing.JToolBar; +import javax.swing.tree.TreePath; + +import com.ql.util.express.DefaultContext; +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.console.FileTree.PathNode; + +public class ConsoleFrame2 + extends JFrame { + private static final long serialVersionUID = 1L; + JPanel contentPane; + BorderLayout borderLayout1 = new BorderLayout(); + JMenuBar jMenuBar1 = new JMenuBar(); + JMenu jMenuFile = new JMenu(); + JMenuItem jMenuFileExit = new JMenuItem(); + JToolBar jToolBar = new JToolBar(); + JButton jButton1 = new JButton(); + ImageIcon image1 = new ImageIcon(com.ql.util.express.console.ConsoleFrame2.class. + getResource("run.png")); + JLabel statusBar = new JLabel(); + JSplitPane jSplitPaneMain = new JSplitPane(); + FileTree jTreeFileSelect = new FileTree(System.getProperty("user.dir")); + JTabbedPane jTabbedPaneContent = new JTabbedPane(); + JPanel jPaneRunner = new JPanel(); + JPanel jPanelHelp = new JPanel(); + JPanel jPanel3 = new JPanel(); + JSplitPane jSplitPaneRun = new JSplitPane(); + BorderLayout borderLayout2 = new BorderLayout(); + JTextArea jTextAreaScript = new JTextArea(); + JScrollPane jScrollPaneScript = new JScrollPane(); + JSplitPane jSplitPaneS_C = new JSplitPane(); + JScrollPane jScrollPaneContext = new JScrollPane(); + JScrollPane jScrollPaneResult = new JScrollPane(); + JTextArea jTextAreaContext = new JTextArea(); + JTextArea jTextAreaResult = new JTextArea(); + JScrollPane jScrollPaneTree = new JScrollPane(); + JPanel jPanelResult = new JPanel(); + BorderLayout borderLayout3 = new BorderLayout(); + JLabel jLabelScript = new JLabel(); + JLabel jLabelResult = new JLabel(); + JLabel jLabelContext = new JLabel(); + JPanel jPanelScript = new JPanel(); + BorderLayout borderLayout4 = new BorderLayout(); + JPanel jPanelContext = new JPanel(); + BorderLayout borderLayout5 = new BorderLayout(); + public ConsoleFrame2() { + try { + setDefaultCloseOperation(EXIT_ON_CLOSE); + jbInit(); +// PrintStream ps = new PrintStream(System.out) { +// public void println(String x) { +// jTextAreaResult.insert(x,jTextAreaResult.getLineCount()); +// } +// }; +// System.setOut(ps); + } + catch (Exception exception) { + exception.printStackTrace(); + } + } + + /** + * Component initialization. + * + * @throws java.lang.Exception + */ + private void jbInit() throws Exception { + contentPane = (JPanel) getContentPane(); + contentPane.setLayout(borderLayout1); + setSize(new Dimension(1000, 600)); + setTitle("QLExpressConsole"); + statusBar.setText(" "); + jMenuFile.setText("File"); + jMenuFileExit.setText("Exit"); + jMenuFileExit.addActionListener(new + ConsoleFrame_jMenuFileExit_ActionAdapter2(this)); + jTreeFileSelect.addMouseListener(new + ConsoleFrame_jTreeFileSelect_mouseAdapter2(this)); + jSplitPaneMain.add(jScrollPaneTree, JSplitPane.LEFT); + jSplitPaneMain.add(jTabbedPaneContent, JSplitPane.RIGHT); + jSplitPaneMain.setOrientation(JSplitPane.HORIZONTAL_SPLIT); + jSplitPaneRun.setOrientation(JSplitPane.VERTICAL_SPLIT); + jSplitPaneRun.setDividerSize(2); + jPaneRunner.setLayout(borderLayout2); + jTextAreaScript.setText(""); + jTextAreaContext.setText(""); + jTextAreaResult.setText(""); + contentPane.setMinimumSize(new Dimension(500, 400)); + contentPane.setPreferredSize(new Dimension(500, 400)); + jButton1.addActionListener(new ConsoleFrame_jButton1_actionAdapter2(this)); + jPanelResult.setLayout(borderLayout3); + jLabelScript.setText("运行脚本"); + jLabelResult.setText("运行结果"); + jLabelContext.setText("脚本上下文"); + jPanelScript.setLayout(borderLayout4); + jPanelContext.setLayout(borderLayout5); + jMenuBar1.add(jMenuFile); + jMenuFile.add(jMenuFileExit); + setJMenuBar(jMenuBar1); + jButton1.setIcon(image1); + jButton1.setToolTipText("执行"); + jToolBar.add(jButton1); + contentPane.add(statusBar, BorderLayout.SOUTH); + contentPane.add(jSplitPaneMain, java.awt.BorderLayout.CENTER); + jTabbedPaneContent.add(jPaneRunner, "执行代码"); + jTabbedPaneContent.add(jPanelHelp, "关键字"); + jTabbedPaneContent.add(jPanel3, "帮助"); + jPaneRunner.add(jSplitPaneRun, java.awt.BorderLayout.CENTER); + jScrollPaneTree.getViewport().add(this.jTreeFileSelect); + jScrollPaneContext.getViewport().add(jTextAreaContext); + jScrollPaneResult.getViewport().add(jTextAreaResult); + jPanelResult.add(jScrollPaneResult, java.awt.BorderLayout.CENTER); + jPanelResult.add(jLabelResult, java.awt.BorderLayout.NORTH); + jPanelScript.add(jLabelScript, java.awt.BorderLayout.NORTH); + jPanelScript.add(jScrollPaneScript, java.awt.BorderLayout.CENTER); + jScrollPaneScript.getViewport().add(jTextAreaScript); + jPanelContext.add(jLabelContext, java.awt.BorderLayout.NORTH); + jPanelContext.add(jScrollPaneContext, java.awt.BorderLayout.CENTER); + jSplitPaneS_C.setDividerSize(2); + jSplitPaneS_C.setLastDividerLocation(200); + jSplitPaneS_C.add(jPanelContext, JSplitPane.RIGHT); + jSplitPaneS_C.add(jPanelScript, JSplitPane.LEFT); + jSplitPaneS_C.setDividerLocation(500); + jSplitPaneRun.add(jPanelResult, JSplitPane.RIGHT); + jSplitPaneRun.add(jSplitPaneS_C, JSplitPane.TOP); + contentPane.add(jToolBar, java.awt.BorderLayout.NORTH); + contentPane.add(jScrollPaneTree, java.awt.BorderLayout.WEST); + jScrollPaneTree.getViewport().add(jTreeFileSelect); + jSplitPaneRun.setDividerLocation(200); + jSplitPaneMain.setDividerLocation(400); + } + + /** + * File | Exit action performed. + * + * @param actionEvent ActionEvent + */ + void jMenuFileExit_actionPerformed(ActionEvent actionEvent) { + System.exit(0); + } + + @SuppressWarnings("unchecked") +public void jButton1_actionPerformed(ActionEvent e) { + String script =jTextAreaScript.getText(); + String[] lines = jTextAreaContext.getText().split("\n"); + String contextText =""; + for(int i =0;i< lines.length;i++){ + if(lines[i].trim().length() >0){ + String[] tempStr = lines[i].trim().split(":"); + if(contextText.length() >0){ + contextText = contextText +","; + } + contextText = contextText +"\"" + tempStr[0] +"\":" + tempStr[1]; + } + } + Object r = null; + StringWriter writer = new StringWriter(); + try { + ExpressRunner runner = new ExpressRunner(false,true); + contextText = "NewMap(" + contextText + ")"; + Map tempMap = (Map)runner.execute(contextText,null,null,false,false); + DefaultContext context = new DefaultContext(); + context.putAll(tempMap); + r = runner.execute(script, context, null,false,true); + writer.write("QL>\n" + + "-------------------原始执行脚本--------------------------------\n" + + script + "\n" + + "-------------------脚本运行结果--------------------------------\n" + + r +"\n" + + "-------------------运行后上下文--------------------------------\n" + + context + + "\nQL>"); + } catch (Exception e1) { + e1.printStackTrace(new PrintWriter(writer)); + + } + //System.out.println(writer.toString()); + jTextAreaResult.setText(writer.toString()); + + } + + public void jTreeFileSelect_mouseClicked(MouseEvent me) { + StringWriter writer = new StringWriter(); + try { + TreePath tp = ((FileTree)me.getSource()).getPathForLocation(me.getX(), me.getY()); + PathNode node = (PathNode)tp.getPath()[tp.getPathCount() -1]; + String fileName = node.getValue(); + ExampleDefine define = ReadExample.readExampleDefine(fileName); + jTextAreaScript.setText(define.getScript()); + jTextAreaContext.setText(define.getContext()); + } catch (Exception e) { + e.printStackTrace(new PrintWriter(writer)); + } + + } +} + +class ConsoleFrame_jTreeFileSelect_mouseAdapter2 + extends MouseAdapter { + private ConsoleFrame2 adaptee; + ConsoleFrame_jTreeFileSelect_mouseAdapter2(ConsoleFrame2 adaptee) { + this.adaptee = adaptee; + } + + public void mouseClicked(MouseEvent e) { + adaptee.jTreeFileSelect_mouseClicked(e); + } +} + +class ConsoleFrame_jButton1_actionAdapter2 + implements ActionListener { + private ConsoleFrame2 adaptee; + ConsoleFrame_jButton1_actionAdapter2(ConsoleFrame2 adaptee) { + this.adaptee = adaptee; + } + + public void actionPerformed(ActionEvent e) { + try { + adaptee.jButton1_actionPerformed(e); + } catch (Exception e1) { + e1.printStackTrace(); + } + } +} + +class ConsoleFrame_jMenuFileExit_ActionAdapter2 + implements ActionListener { + ConsoleFrame2 adaptee; + + ConsoleFrame_jMenuFileExit_ActionAdapter2(ConsoleFrame2 adaptee) { + this.adaptee = adaptee; + } + + public void actionPerformed(ActionEvent actionEvent) { + adaptee.jMenuFileExit_actionPerformed(actionEvent); + } +} diff --git a/src/main/java/com/ql/util/express/console/ExampleDefine.java b/src/main/java/com/ql/util/express/console/ExampleDefine.java new file mode 100644 index 0000000000000000000000000000000000000000..6648b0852c064f6c0ed94d1c7494187a1e7ebcaf --- /dev/null +++ b/src/main/java/com/ql/util/express/console/ExampleDefine.java @@ -0,0 +1,20 @@ +package com.ql.util.express.console; + +public class ExampleDefine { + private String script; + private String context; + + public ExampleDefine(String aScript, String aContext) { + this.script = aScript; + this.context = aContext; + } + + public String getScript() { + return script; + } + + public String getContext() { + return context; + } + +} diff --git a/src/main/java/com/ql/util/express/console/FileTree.java b/src/main/java/com/ql/util/express/console/FileTree.java new file mode 100644 index 0000000000000000000000000000000000000000..54947ddf889a2f5c1d65ee622a866ea2fe1058f1 --- /dev/null +++ b/src/main/java/com/ql/util/express/console/FileTree.java @@ -0,0 +1,123 @@ +package com.ql.util.express.console; + +import java.awt.Component; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.File; + +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JLabel; +import javax.swing.JTree; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeCellRenderer; +import javax.swing.tree.TreePath; +/** +*

Description: 系统目录树,动态生成,解决载入慢的问题

+*/ +public class FileTree extends JTree { + private static final long serialVersionUID = 1L; + private DefaultTreeModel model; + public FileTree (String dir) { + this.initData(dir); + this.addMouseListener(new MouseAdapter(){ + public void mousePressed(MouseEvent e){ + node_mouseAction(e); + } + }); + } + private void node_mouseAction(MouseEvent e){ + int row = this.getRowForLocation(e.getX(), e.getY()); + PathNode pathNode =null; + if(row != -1){ + TreePath path = this.getPathForRow(row); + pathNode = (PathNode)path.getLastPathComponent(); + if(pathNode.isFolder()&&pathNode.getChildCount()==0){ + builderNode(pathNode); + this.expandPath(path); + } + } + } + private PathNode builderNode(PathNode pathNode){ + String filePath= pathNode.getValue().toString(); + File file=new File(filePath); + File[] files=file.listFiles(); + for(int i=0;i forStack, ExpressNode node,boolean isRoot) + throws Exception { + if (node.isTypeEqualsOrChild("STAT_SEMICOLON") + &&result.getCurrentPoint() >=0 && result.getInstruction(result.getCurrentPoint()) instanceof InstructionClearDataStack == false) { + result.addInstruction(new InstructionClearDataStack()); + } + + int tmpPoint = result.getCurrentPoint()+1; + boolean returnVal = false; + boolean hasDef = false; + for(ExpressNode tmpNode : node.getChildren()){ + boolean tmpHas = aCompile.createInstructionSetPrivate(result,forStack,tmpNode,false); + hasDef = hasDef || tmpHas; + } + if (hasDef == true&& isRoot == false + && node.getTreeType().isEqualsOrChild("STAT_BLOCK")){ + result.insertInstruction(tmpPoint,new InstructionOpenNewArea()); + result.insertInstruction(result.getCurrentPoint() + 1,new InstructionCloseNewArea()); + returnVal = false; + }else{ + returnVal = hasDef; + } + return returnVal; + } +} diff --git a/src/main/java/com/ql/util/express/instruction/BreakInstructionFactory.java b/src/main/java/com/ql/util/express/instruction/BreakInstructionFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..9c785af459cbf97ff34f1d89f18e15fbebaf1250 --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/BreakInstructionFactory.java @@ -0,0 +1,20 @@ +package com.ql.util.express.instruction; + +import java.util.Stack; + +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.InstructionSet; +import com.ql.util.express.instruction.detail.InstructionGoTo; +import com.ql.util.express.parse.ExpressNode; + +public class BreakInstructionFactory extends InstructionFactory { + public boolean createInstruction(ExpressRunner aCompile,InstructionSet result, + Stack forStack, ExpressNode node,boolean isRoot) + throws Exception { + InstructionGoTo breakInstruction = new InstructionGoTo(result.getCurrentPoint()+1); + breakInstruction.name = "break"; + forStack.peek().breakList.add(breakInstruction); + result.addInstruction(breakInstruction); + return false; + } +} diff --git a/src/main/java/com/ql/util/express/instruction/CallFunctionInstructionFactory.java b/src/main/java/com/ql/util/express/instruction/CallFunctionInstructionFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..6a5e66ae718ac6ebbff8b9c949badf75dce05259 --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/CallFunctionInstructionFactory.java @@ -0,0 +1,40 @@ +package com.ql.util.express.instruction; + +import java.util.Stack; + +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.InstructionSet; +import com.ql.util.express.instruction.detail.InstructionCallSelfDefineFunction; +import com.ql.util.express.instruction.detail.InstructionOperator; +import com.ql.util.express.instruction.op.OperatorBase; +import com.ql.util.express.parse.ExpressNode; + + +public class CallFunctionInstructionFactory extends InstructionFactory{ + public boolean createInstruction(ExpressRunner aCompile, + InstructionSet result, Stack forStack, + ExpressNode node, boolean isRoot) throws Exception { + ExpressNode[] children = node.getChildren(); + String functionName = children[0].getValue(); + boolean returnVal = false; + children = node.getChildren(); + for (int i = 1; i < children.length; i++) { + boolean tmpHas = aCompile.createInstructionSetPrivate(result, + forStack, children[i], false); + returnVal = returnVal || tmpHas; + } + + OperatorBase op = aCompile.getOperatorFactory().getOperator( + functionName); + int opNum = children.length -1; + if (op != null) { + result.addInstruction(new InstructionOperator(op,opNum )); + } else { + result.addInstruction(new InstructionCallSelfDefineFunction( + functionName,opNum)); + } + return returnVal; + } +} + + diff --git a/src/main/java/com/ql/util/express/instruction/CastInstructionFactory.java b/src/main/java/com/ql/util/express/instruction/CastInstructionFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..079ca7fad8ef8dc5525aa0e1e5ca158462f609b8 --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/CastInstructionFactory.java @@ -0,0 +1,33 @@ +package com.ql.util.express.instruction; + +import java.util.Stack; + +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.InstructionSet; +import com.ql.util.express.instruction.detail.InstructionOperator; +import com.ql.util.express.instruction.op.OperatorBase; +import com.ql.util.express.parse.ExpressNode; + + +public class CastInstructionFactory extends InstructionFactory{ + public boolean createInstruction(ExpressRunner aCompile,InstructionSet result,Stack forStack, ExpressNode node,boolean isRoot) + throws Exception { + boolean returnVal = false; + OperatorBase op = aCompile.getOperatorFactory().newInstance(node); + ExpressNode[] children = node.getChildren(); + if(children.length ==0){ + throw new Exception("扩展类型不存在"); + }else if(children.length > 2) { + throw new Exception("扩展操作只能有一个类型为Class的操作数"); + }else if(children[0].getNodeType().isEqualsOrChild("CONST_CLASS") == false){ + throw new Exception("扩展操作只能有一个类型为Class的操作数,当前的数据类型是:" + children[0].getNodeType().getName()); + } + + for(int i =0;i < children.length;i++){ + boolean tmpHas = aCompile.createInstructionSetPrivate(result,forStack,children[i],false); + returnVal = returnVal || tmpHas; + } + result.addInstruction(new InstructionOperator(op,children.length)); + return returnVal; + } +} diff --git a/src/main/java/com/ql/util/express/instruction/ConstDataInstructionFactory.java b/src/main/java/com/ql/util/express/instruction/ConstDataInstructionFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..404aef3a97721b7e14875648ea62d7cbd5a2a424 --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/ConstDataInstructionFactory.java @@ -0,0 +1,27 @@ +package com.ql.util.express.instruction; + +import java.util.Stack; + +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.InstructionSet; +import com.ql.util.express.OperateData; +import com.ql.util.express.instruction.detail.InstructionConstData; +import com.ql.util.express.instruction.opdata.OperateClass; +import com.ql.util.express.parse.ExpressNode; + +public class ConstDataInstructionFactory extends InstructionFactory { + public OperateData genOperateData(ExpressNode node) { + if (node.isTypeEqualsOrChild("CONST_CLASS")) { + return new OperateClass(node.getValue(), (Class) node.getObjectValue()); + } else { + return new OperateData(node.getObjectValue(), node.getObjectValue().getClass()); + } + } + + public boolean createInstruction(ExpressRunner aCompile, + InstructionSet result, Stack forStack, + ExpressNode node, boolean isRoot) throws Exception { + result.addInstruction(new InstructionConstData(genOperateData(node))); + return false; + } +} diff --git a/src/main/java/com/ql/util/express/instruction/ContinueInstructionFactory.java b/src/main/java/com/ql/util/express/instruction/ContinueInstructionFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..502b23b02f3d9c203245d25406b3320407d4238a --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/ContinueInstructionFactory.java @@ -0,0 +1,20 @@ +package com.ql.util.express.instruction; + +import java.util.Stack; + +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.InstructionSet; +import com.ql.util.express.instruction.detail.InstructionGoTo; +import com.ql.util.express.parse.ExpressNode; + +public class ContinueInstructionFactory extends InstructionFactory { + public boolean createInstruction(ExpressRunner aCompile,InstructionSet result, + Stack forStack, ExpressNode node,boolean isRoot) + throws Exception { + InstructionGoTo continueInstruction = new InstructionGoTo(result.getCurrentPoint()+1); + continueInstruction.name = "continue"; + forStack.peek().continueList.add(continueInstruction); + result.addInstruction(continueInstruction); + return false; + } +} diff --git a/src/main/java/com/ql/util/express/instruction/DefineInstructionFactory.java b/src/main/java/com/ql/util/express/instruction/DefineInstructionFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..853ae327fede91f8ce5d024beae77435d4fe1368 --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/DefineInstructionFactory.java @@ -0,0 +1,56 @@ +package com.ql.util.express.instruction; + +import java.util.Stack; + +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.ExpressUtil; +import com.ql.util.express.InstructionSet; +import com.ql.util.express.instruction.detail.InstructionOperator; +import com.ql.util.express.instruction.op.OperatorBase; +import com.ql.util.express.parse.ExpressNode; + + +class DefineInstructionFactory extends InstructionFactory{ + public boolean createInstruction(ExpressRunner aCompile,InstructionSet result,Stack forStack, ExpressNode node,boolean isRoot) + throws Exception { + boolean returnVal = false; + ExpressNode[] children = node.getChildren(); + int [] finishPoint = new int[children.length]; + int arrayDimeCount =0; + String tempStr=""; + for(int i = children.length - 2;i>0;i--){ + ExpressNode tmpNode = children[i]; + if(tmpNode.isTypeEqualsOrChild("[]")){ + arrayDimeCount = arrayDimeCount +1; + node.getLeftChildren().remove(i); + tempStr = tempStr +"[]"; + }else{ + throw new Exception("不正确的类型定义"); + } + } + if(arrayDimeCount > 0){ + node.getLeftChildren().get(0).setValue(node.getLeftChildren().get(0).getValue() + tempStr); + node.getLeftChildren().get(0).setOrgiValue(node.getLeftChildren().get(0).getOrgiValue() + tempStr); + Object objValue = node.getLeftChildren().get(0).getObjectValue(); + if(objValue instanceof Class){ + Class tmpClass = ExpressUtil.getJavaClass(ExpressUtil.getClassName((Class)objValue) + tempStr); + node.getLeftChildren().get(0).setObjectValue(tmpClass); + }else{ + node.getLeftChildren().get(0).setObjectValue(node.getLeftChildren().get(0).getObjectValue()+ tempStr); + } + } + + children = node.getChildren(); + for(int i =0;i < children.length;i++){ + ExpressNode tmpNode = children[i]; + boolean tmpHas = aCompile.createInstructionSetPrivate(result,forStack,tmpNode,false); + returnVal = returnVal || tmpHas; + finishPoint[i] = result.getCurrentPoint(); + } + OperatorBase op = aCompile.getOperatorFactory().newInstance(node); + result.addInstruction(new InstructionOperator(op, children.length)); + returnVal = true; + return returnVal; + } +} + diff --git a/src/main/java/com/ql/util/express/instruction/FieldCallInstructionFactory.java b/src/main/java/com/ql/util/express/instruction/FieldCallInstructionFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..9cbb131f444619bbb54dc83026eaa23d862e316c --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/FieldCallInstructionFactory.java @@ -0,0 +1,36 @@ +package com.ql.util.express.instruction; + +import java.util.Stack; + +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.InstructionSet; +import com.ql.util.express.instruction.detail.InstructionOperator; +import com.ql.util.express.instruction.op.OperatorBase; +import com.ql.util.express.instruction.op.OperatorField; +import com.ql.util.express.parse.ExpressNode; + + +public class FieldCallInstructionFactory extends InstructionFactory { + public boolean createInstruction(ExpressRunner aCompile, + InstructionSet result, Stack forStack, + ExpressNode node, boolean isRoot) throws Exception { + boolean returnVal = false; + ExpressNode[] children = node.getChildren(); + //处理对象 + boolean tmpHas = aCompile.createInstructionSetPrivate(result,forStack, children[0], false); + returnVal = returnVal || tmpHas; + + //处理属性名称 + if(children[1].getNodeType().getName().equalsIgnoreCase("CONST_STRING") == false){ + throw new Exception("对象属性名称不是字符串常量:" + children[1] ); + } + + String fieldName = (String)children[1].getObjectValue(); + + + OperatorBase op = new OperatorField(fieldName); + result.addInstruction(new InstructionOperator(op,1)); + return returnVal; + } + +} diff --git a/src/main/java/com/ql/util/express/instruction/ForInstructionFactory.java b/src/main/java/com/ql/util/express/instruction/ForInstructionFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..0c1e5983b6d329015b38124390b3e0e664a22443 --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/ForInstructionFactory.java @@ -0,0 +1,89 @@ +package com.ql.util.express.instruction; + +import java.util.Stack; + +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.InstructionSet; +import com.ql.util.express.instruction.detail.InstructionCloseNewArea; +import com.ql.util.express.instruction.detail.InstructionGoTo; +import com.ql.util.express.instruction.detail.InstructionGoToWithCondition; +import com.ql.util.express.instruction.detail.InstructionOpenNewArea; +import com.ql.util.express.parse.ExpressNode; + +public class ForInstructionFactory extends InstructionFactory { + public boolean createInstruction(ExpressRunner aCompile,InstructionSet result, + Stack forStack, ExpressNode node,boolean isRoot) + throws Exception { + if(node.getChildren().length < 2){ + throw new Exception("for 操作符至少需要2个操作数 " ); + }else if(node.getChildren().length > 2){ + throw new Exception("for 操作符最多只有2个操作数 " ); + } + if(node.getChildren()[0].getChildren()!= null && node.getChildren()[0].getChildren().length > 3){ + throw new Exception("循环语句的设置不合适:" + node.getChildren()[0]); + } + //生成作用域开始指令 + result.addInstruction(new InstructionOpenNewArea()); + forStack.push(new ForRelBreakContinue()); + + //生成条件语句部分指令 + ExpressNode conditionNode = node.getChildren()[0]; + int nodePoint = 0; + if (conditionNode.getChildren() != null && conditionNode.getChildren().length == 3){//变量定义,判断,自增都存在 + int tempPoint = result.getCurrentPoint(); + aCompile.createInstructionSetPrivate(result,forStack,conditionNode.getChildren()[0],false); + if(result.getCurrentPoint() > tempPoint){ + nodePoint = nodePoint + 1; + } + } + //循环的开始的位置 + int loopStartPoint = result.getCurrentPoint()+ 1; + + //有条件语句 + InstructionGoToWithCondition conditionInstruction=null; + if(conditionNode.getChildren() != null + && (conditionNode.getChildren().length == 1 + || conditionNode.getChildren().length == 2 + || conditionNode.getChildren().length == 3) + ) { + aCompile.createInstructionSetPrivate(result,forStack,conditionNode.getChildren()[nodePoint],false); + //跳转的位置需要根据后续的指令情况决定 + conditionInstruction = new InstructionGoToWithCondition(false,-1,true); + result.insertInstruction(result.getCurrentPoint()+1,conditionInstruction); + nodePoint = nodePoint+ 1; + } + int conditionPoint = result.getCurrentPoint(); + //生成循环体的代码 + aCompile.createInstructionSetPrivate(result,forStack,node.getChildren()[1],false); + + int selfAddPoint = result.getCurrentPoint()+1; + //生成自增代码指令 + if(conditionNode.getChildren()!= null &&( + conditionNode.getChildren().length == 2 || conditionNode.getChildren().length == 3 + )){ + aCompile.createInstructionSetPrivate(result,forStack,conditionNode.getChildren()[nodePoint],false); + } + //增加一个无条件跳转 + InstructionGoTo reStartGoto = new InstructionGoTo(loopStartPoint - (result.getCurrentPoint() + 1)); + result.addInstruction(reStartGoto); + + //修改条件判断的跳转位置 + if(conditionInstruction != null){ + conditionInstruction.setOffset( result.getCurrentPoint() - conditionPoint + 1); + } + + //修改Break和Continue指令的跳转位置,循环出堆 + ForRelBreakContinue rel = forStack.pop(); + for(InstructionGoTo item:rel.breakList){ + item.setOffset(result.getCurrentPoint() - item.getOffset()) ; + } + for(InstructionGoTo item:rel.continueList){ + item.setOffset(selfAddPoint - item.getOffset() - 1); + } + + //生成作用域结束指令 + result.addInstruction(new InstructionCloseNewArea()); + + return false; + } +} diff --git a/src/main/java/com/ql/util/express/instruction/ForRelBreakContinue.java b/src/main/java/com/ql/util/express/instruction/ForRelBreakContinue.java new file mode 100644 index 0000000000000000000000000000000000000000..fed29a62496095c645575b0c1b7f4b6c3942e8b7 --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/ForRelBreakContinue.java @@ -0,0 +1,12 @@ +package com.ql.util.express.instruction; + +import java.util.ArrayList; +import java.util.List; + +import com.ql.util.express.instruction.detail.InstructionGoTo; + +public class ForRelBreakContinue{ + List breakList = new ArrayList(); + List continueList = new ArrayList(); + +} diff --git a/src/main/java/com/ql/util/express/instruction/FunctionInstructionFactory.java b/src/main/java/com/ql/util/express/instruction/FunctionInstructionFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..8616024fd89d691102a5fc2e5e38cbd15d9750e9 --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/FunctionInstructionFactory.java @@ -0,0 +1,49 @@ +package com.ql.util.express.instruction; + +import java.util.Stack; + +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.InstructionSet; +import com.ql.util.express.instruction.opdata.OperateDataLocalVar; +import com.ql.util.express.parse.ExpressNode; + +public class FunctionInstructionFactory extends InstructionFactory { + public boolean createInstruction(ExpressRunner aCompile,InstructionSet result, + Stack forStack, ExpressNode node,boolean isRoot) + throws Exception { + ExpressNode[] children = node.getChildren(); + if(children.length != 3){ + throw new Exception("funciton 操作符需要3个操作数 " ); + } + String functionName =children[0].getValue(); + ExpressNode[] varDefines = children[1].getChildren(); + int point =0; + + String instructionSetType =""; + if (node.isTypeEqualsOrChild("class")) { + instructionSetType = InstructionSet.TYPE_CLASS; + } else { + instructionSetType = InstructionSet.TYPE_FUNCTION; + } + InstructionSet functionSet = new InstructionSet(instructionSetType); + + while(point varClass = (Class)varDefines[point].getChildren()[0].getObjectValue(); + String varName = varDefines[point].getChildren()[1].getValue(); + OperateDataLocalVar tmpVar = new OperateDataLocalVar(varName,varClass); + functionSet.addParameter(tmpVar); + point = point + 1; + } + + ExpressNode functionRoot = new ExpressNode(aCompile.getNodeTypeManager().findNodeType("FUNCTION_DEFINE"),"function-" + functionName); + for(ExpressNode tempNode : children[2].getChildren()){ + functionRoot.addLeftChild(tempNode); + } + aCompile.createInstructionSet(functionRoot,functionSet); + result.addMacroDefine(functionName, new FunctionInstructionSet(functionName,instructionSetType,functionSet)); + return false; + } +} diff --git a/src/main/java/com/ql/util/express/instruction/FunctionInstructionSet.java b/src/main/java/com/ql/util/express/instruction/FunctionInstructionSet.java new file mode 100644 index 0000000000000000000000000000000000000000..72ddc840aa04bf80014f2192915eea2c9ad290f2 --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/FunctionInstructionSet.java @@ -0,0 +1,19 @@ +package com.ql.util.express.instruction; + +import java.io.Serializable; + +import com.ql.util.express.InstructionSet; + + +public class FunctionInstructionSet implements Serializable{ + private static final long serialVersionUID = 8735208809492617401L; + public String name; + public String type; + public InstructionSet instructionSet; + public FunctionInstructionSet(String aName,String aType,InstructionSet aInstructionSet){ + this.name = aName; + this.type = aType; + this.instructionSet = aInstructionSet; + } + +} diff --git a/src/main/java/com/ql/util/express/instruction/IOperateDataCache.java b/src/main/java/com/ql/util/express/instruction/IOperateDataCache.java new file mode 100644 index 0000000000000000000000000000000000000000..fc5ec205aba50bc1f522bced0f29d98954457be2 --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/IOperateDataCache.java @@ -0,0 +1,29 @@ +package com.ql.util.express.instruction; + +import com.ql.util.express.CallResult; +import com.ql.util.express.ExpressLoader; +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.IExpressContext; +import com.ql.util.express.InstructionSet; +import com.ql.util.express.InstructionSetContext; +import com.ql.util.express.OperateData; +import com.ql.util.express.RunEnvironment; +import com.ql.util.express.instruction.opdata.OperateDataArrayItem; +import com.ql.util.express.instruction.opdata.OperateDataAttr; +import com.ql.util.express.instruction.opdata.OperateDataField; +import com.ql.util.express.instruction.opdata.OperateDataKeyValue; +import com.ql.util.express.instruction.opdata.OperateDataLocalVar; + +public interface IOperateDataCache { + public OperateData fetchOperateData(Object obj, Class aType); + public OperateDataAttr fetchOperateDataAttr(String name, Class aType); + public OperateDataLocalVar fetchOperateDataLocalVar(String name, Class aType); + public OperateDataField fetchOperateDataField(Object aFieldObject,String aFieldName); + public OperateDataArrayItem fetchOperateDataArrayItem(OperateData aArrayObject,int aIndex); + public OperateDataKeyValue fetchOperateDataKeyValue(OperateData aKey, OperateData aValue); + public RunEnvironment fetRunEnvironment(InstructionSet aInstructionSet,InstructionSetContext aContext,boolean aIsTrace); + public CallResult fetchCallResult(Object aReturnValue,boolean aIsExit); + public InstructionSetContext fetchInstructionSetContext(boolean aIsExpandToParent,ExpressRunner aRunner,IExpressContext aParent,ExpressLoader aExpressLoader,boolean aIsSupportDynamicFieldName); + public void resetCache(); + public long getFetchCount(); + } diff --git a/src/main/java/com/ql/util/express/instruction/IfInstructionFactory.java b/src/main/java/com/ql/util/express/instruction/IfInstructionFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..b4eea2a131f8184e4d8be9f97451d4b416b77a0d --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/IfInstructionFactory.java @@ -0,0 +1,46 @@ +package com.ql.util.express.instruction; + +import java.util.Stack; + +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.InstructionSet; +import com.ql.util.express.instruction.detail.InstructionGoTo; +import com.ql.util.express.instruction.detail.InstructionGoToWithCondition; +import com.ql.util.express.parse.ExpressNode; + +public class IfInstructionFactory extends InstructionFactory { + public boolean createInstruction(ExpressRunner aCompile,InstructionSet result, + Stack forStack, ExpressNode node,boolean isRoot) + throws Exception { + ExpressNode[] oldChildren = node.getChildren(); + if(oldChildren.length < 2){ + throw new Exception("if 操作符至少需要2个操作数 " ); + }else if(oldChildren.length > 5){ + throw new Exception("if 操作符最多只有5个操作数 " ); + } + ExpressNode[] children = new ExpressNode[3]; + int point = 0; + for(int i=0;i forStack, + ExpressNode node, boolean isRoot) throws Exception { + ExpressNode[] children = node.getChildren(); + if (children[1].isTypeEqualsOrChild("CHILD_EXPRESS")) { + node.getLeftChildren().remove(1); + ExpressNode[] parameterList = children[1].getChildren(); + for (int i = 0; i < parameterList.length; i++) { + node.getLeftChildren().add(parameterList[i]); + } + } + + boolean returnVal = false; + children = node.getChildren(); + for (int i = 0; i < children.length; i++) { + boolean tmpHas = aCompile.createInstructionSetPrivate(result,forStack, children[i], false); + returnVal = returnVal || tmpHas; + } + OperatorBase op = aCompile.getOperatorFactory().newInstance(node); + result.addInstruction(new InstructionOperator(op, children.length)); + return returnVal; + } +} diff --git a/src/main/java/com/ql/util/express/instruction/InstructionFactory.java b/src/main/java/com/ql/util/express/instruction/InstructionFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..2d430f4e77030797cec59e1d9c77881277056681 --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/InstructionFactory.java @@ -0,0 +1,29 @@ +package com.ql.util.express.instruction; + +import java.util.HashMap; +import java.util.Map; +import java.util.Stack; + +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.InstructionSet; +import com.ql.util.express.parse.ExpressNode; + +public abstract class InstructionFactory { + private static Map instructionFactory = new HashMap(); + + public static InstructionFactory getInstructionFactory(String factory) { + try { + InstructionFactory result = instructionFactory.get(factory); + if (result == null) { + result = (InstructionFactory) Class.forName(factory) + .newInstance(); + } + return result; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + public abstract boolean createInstruction(ExpressRunner aCompile,InstructionSet result, + Stack forStack, ExpressNode node,boolean isRoot) + throws Exception; +} diff --git a/src/main/java/com/ql/util/express/instruction/KeyValueInstructionFactory.java b/src/main/java/com/ql/util/express/instruction/KeyValueInstructionFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..13953f35c3e4ef2b2a989344e44087cdc28ab76b --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/KeyValueInstructionFactory.java @@ -0,0 +1,46 @@ +package com.ql.util.express.instruction; + +import java.util.Stack; + +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.InstructionSet; +import com.ql.util.express.instruction.detail.InstructionOperator; +import com.ql.util.express.instruction.op.OperatorBase; +import com.ql.util.express.parse.ExpressNode; + + +class KeyValueInstructionFactory extends InstructionFactory{ + public boolean createInstruction(ExpressRunner aCompile,InstructionSet result,Stack forStack, ExpressNode node,boolean isRoot) + throws Exception { + boolean returnVal = false; + ExpressNode[] children = node.getChildren(); + if( node.getParent() != null && node.getParent().isTypeEqualsOrChild("STATEMENT")){ + children[0].setNodeType(aCompile.getNodeTypeManager().findNodeType("CONST_STRING")); + children[0].setTreeType(aCompile.getNodeTypeManager().findNodeType("CONST")); + children[0].setObjectValue(children[0].getValue()); + } + if( node.getParent() != null && node.getParent().isTypeEqualsOrChild("STATEMENT") && children[1].isTypeEqualsOrChild("STAT_BLOCK")){ + returnVal = new MacroInstructionFactory().createInstruction(aCompile, result, forStack, node, isRoot); + } else if (node.getParent() != null&& node.getParent().isTypeEqualsOrChild("STATEMENT")) { + for(int i =0;i < children.length;i++){ + ExpressNode tmpNode = children[i]; + boolean tmpHas = aCompile.createInstructionSetPrivate(result,forStack,tmpNode,false); + returnVal = returnVal || tmpHas; + } + OperatorBase op = aCompile.getOperatorFactory().newInstance("alias"); + result.addInstruction(new InstructionOperator(op, children.length)); + returnVal = true; + }else{ + for(int i =0;i < children.length;i++){ + ExpressNode tmpNode = children[i]; + boolean tmpHas = aCompile.createInstructionSetPrivate(result,forStack,tmpNode,false); + returnVal = returnVal || tmpHas; + } + + OperatorBase op = aCompile.getOperatorFactory().newInstance(node); + result.addInstruction(new InstructionOperator(op,children.length)); + } + return returnVal; + } +} + diff --git a/src/main/java/com/ql/util/express/instruction/LoadAttrInstructionFactory.java b/src/main/java/com/ql/util/express/instruction/LoadAttrInstructionFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..abf4971281d932fd0f964222692ffec60185a9a1 --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/LoadAttrInstructionFactory.java @@ -0,0 +1,27 @@ +package com.ql.util.express.instruction; + +import java.util.Stack; + +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.InstructionSet; +import com.ql.util.express.instruction.detail.InstructionCallMacro; +import com.ql.util.express.instruction.detail.InstructionLoadAttr; +import com.ql.util.express.parse.ExpressNode; + + +public class LoadAttrInstructionFactory extends InstructionFactory { + public boolean createInstruction(ExpressRunner aCompile,InstructionSet result, + Stack forStack, ExpressNode node,boolean isRoot) + throws Exception{ + FunctionInstructionSet functionSet = result.getMacroDefine(node.getValue()); + if(functionSet != null){//是宏定义 + result.insertInstruction(result.getCurrentPoint()+1, new InstructionCallMacro(node.getValue())); + }else{ + result.addInstruction(new InstructionLoadAttr(node.getValue())); + if(node.getChildren().length >0){ + throw new Exception("表达式设置错误"); + } + } + return false; + } +} diff --git a/src/main/java/com/ql/util/express/instruction/MacroInstructionFactory.java b/src/main/java/com/ql/util/express/instruction/MacroInstructionFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..3f351946dcc48f765c6ed53265f7f6f229ecc66f --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/MacroInstructionFactory.java @@ -0,0 +1,23 @@ +package com.ql.util.express.instruction; + +import java.util.Stack; + +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.InstructionSet; +import com.ql.util.express.parse.ExpressNode; + +public class MacroInstructionFactory extends InstructionFactory { + public boolean createInstruction(ExpressRunner aCompile,InstructionSet result, + Stack forStack, ExpressNode node,boolean isRoot) + throws Exception { + ExpressNode[] children = node.getChildren(); + String macroName =children[0].getValue(); + ExpressNode macroRoot = new ExpressNode(aCompile.getNodeTypeManager().findNodeType("FUNCTION_DEFINE"),"macro-" + macroName); + for(ExpressNode tempNode : children[1].getChildren()){ + macroRoot.addLeftChild(tempNode); + } + InstructionSet macroInstructionSet = aCompile.createInstructionSet(macroRoot,InstructionSet.TYPE_MARCO); + result.addMacroDefine(macroName, new FunctionInstructionSet(macroName,"macro",macroInstructionSet)); + return false; + } +} diff --git a/src/main/java/com/ql/util/express/instruction/MethodCallInstructionFactory.java b/src/main/java/com/ql/util/express/instruction/MethodCallInstructionFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..3e4a197f470e63b786556ece8ab39a7ac51e71d0 --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/MethodCallInstructionFactory.java @@ -0,0 +1,37 @@ +package com.ql.util.express.instruction; + +import java.util.Stack; + +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.InstructionSet; +import com.ql.util.express.instruction.detail.InstructionOperator; +import com.ql.util.express.instruction.op.OperatorBase; +import com.ql.util.express.instruction.op.OperatorMethod; +import com.ql.util.express.parse.ExpressNode; + + +public class MethodCallInstructionFactory extends InstructionFactory { + public boolean createInstruction(ExpressRunner aCompile, + InstructionSet result, Stack forStack, + ExpressNode node, boolean isRoot) throws Exception { + boolean returnVal = false; + ExpressNode[] children = node.getChildren(); + //处理对象 + boolean tmpHas = aCompile.createInstructionSetPrivate(result,forStack, children[0], false); + returnVal = returnVal || tmpHas; + //处理方法名称 + if(children[1].getNodeType().getName().equalsIgnoreCase("CONST_STRING") == false){ + throw new Exception("对象方法名称不是字符串常量:" + children[1] ); + } + String methodName = (String)children[1].getObjectValue(); + //处理方法参数 + for (int i = 2; i < children.length; i++) { + tmpHas = aCompile.createInstructionSetPrivate(result,forStack, children[i], false); + returnVal = returnVal || tmpHas; + } + OperatorBase op = new OperatorMethod(methodName); + result.addInstruction(new InstructionOperator(op, children.length - 1)); + return returnVal; + } + +} diff --git a/src/main/java/com/ql/util/express/instruction/NewInstructionFactory.java b/src/main/java/com/ql/util/express/instruction/NewInstructionFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..62dbe5bc039b9bbdfc8eec7a9c68399204c4d8b2 --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/NewInstructionFactory.java @@ -0,0 +1,40 @@ +package com.ql.util.express.instruction; + +import java.util.Stack; + +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.ExpressUtil; +import com.ql.util.express.InstructionSet; +import com.ql.util.express.instruction.detail.InstructionOperator; +import com.ql.util.express.instruction.op.OperatorBase; +import com.ql.util.express.parse.ExpressNode; + + +public class NewInstructionFactory extends InstructionFactory{ + public boolean createInstruction(ExpressRunner aCompile, + InstructionSet result, Stack forStack, + ExpressNode node, boolean isRoot) throws Exception { + OperatorBase op = aCompile.getOperatorFactory().newInstance("new"); + ExpressNode[] children = node.getChildren(); + if (node.isTypeEqualsOrChild("NEW_ARRAY")) { + String tempStr = children[0].getValue(); + for (int i = 0; i < children.length - 1; i++) { + tempStr = tempStr + "[]"; + } + children[0].setValue(tempStr); + children[0].setOrgiValue(tempStr); + children[0].setObjectValue(ExpressUtil.getJavaClass(tempStr)); + }else if (node.isTypeEqualsOrChild("anonymousNewArray")) { + op = aCompile.getOperatorFactory().newInstance("anonymousNewArray"); + } + + boolean returnVal = false; + children = node.getChildren();// 需要重新获取数据 + for (int i = 0; i < children.length; i++) { + boolean tmpHas = aCompile.createInstructionSetPrivate(result,forStack, children[i], false); + returnVal = returnVal || tmpHas; + } + result.addInstruction(new InstructionOperator(op, children.length)); + return returnVal; + } +} diff --git a/src/main/java/com/ql/util/express/instruction/NewVClassInstructionFactory.java b/src/main/java/com/ql/util/express/instruction/NewVClassInstructionFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..673ddd42875e434baad11683a5e53ce2906e083c --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/NewVClassInstructionFactory.java @@ -0,0 +1,25 @@ +package com.ql.util.express.instruction; + +import java.util.Stack; + +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.InstructionSet; +import com.ql.util.express.instruction.detail.InstructionNewVirClass; +import com.ql.util.express.parse.ExpressNode; + + +public class NewVClassInstructionFactory extends InstructionFactory{ + public boolean createInstruction(ExpressRunner aCompile, + InstructionSet result, Stack forStack, + ExpressNode node, boolean isRoot) throws Exception { + ExpressNode[] children = node.getChildren(); + boolean returnVal = false; + String virClassName = children[0].getValue(); + for (int i = 1; i < children.length; i++) { + boolean tmpHas = aCompile.createInstructionSetPrivate(result,forStack, children[i], false); + returnVal = returnVal || tmpHas; + } + result.addInstruction(new InstructionNewVirClass(virClassName, children.length -1)); + return returnVal; + } +} diff --git a/src/main/java/com/ql/util/express/instruction/NullInstructionFactory.java b/src/main/java/com/ql/util/express/instruction/NullInstructionFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..d3d41299136f4c6c96107fa30b4d016ef87eaced --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/NullInstructionFactory.java @@ -0,0 +1,15 @@ +package com.ql.util.express.instruction; + +import java.util.Stack; + +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.InstructionSet; +import com.ql.util.express.parse.ExpressNode; + +public class NullInstructionFactory extends InstructionFactory { + public boolean createInstruction(ExpressRunner aCompile,InstructionSet result, + Stack forStack, ExpressNode node,boolean isRoot) + throws Exception { + return false; + } +} diff --git a/src/main/java/com/ql/util/express/instruction/OperateDataCacheImpl.java b/src/main/java/com/ql/util/express/instruction/OperateDataCacheImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..98c92ad893286ee34f095b3b929a6600a0524400 --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/OperateDataCacheImpl.java @@ -0,0 +1,208 @@ +package com.ql.util.express.instruction; + +import com.ql.util.express.CallResult; +import com.ql.util.express.ExpressLoader; +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.IExpressContext; +import com.ql.util.express.InstructionSet; +import com.ql.util.express.InstructionSetContext; +import com.ql.util.express.OperateData; +import com.ql.util.express.RunEnvironment; +import com.ql.util.express.instruction.opdata.OperateDataArrayItem; +import com.ql.util.express.instruction.opdata.OperateDataAttr; +import com.ql.util.express.instruction.opdata.OperateDataField; +import com.ql.util.express.instruction.opdata.OperateDataKeyValue; +import com.ql.util.express.instruction.opdata.OperateDataLocalVar; + +public class OperateDataCacheImpl implements IOperateDataCache{ + OperateData[] dataList; + OperateDataAttr[] attrList; + OperateDataLocalVar[] localVarList; + OperateDataField[] fieldList; + OperateDataArrayItem[] arrayList; + OperateDataKeyValue[] keyValueList; + RunEnvironment[] environmentList; + CallResult[] callResultList; + InstructionSetContext[] contextList; + + int dataPoint = 0; + int attrPoint = 0; + int localVarPoint =0; + int fieldPoint =0; + int arrayPoint =0; + int keyValuePoint=0; + int environmentPoint =0; + int callResultPoint = 0; + int contextPoint =0; + + int length; + public OperateDataCacheImpl(int len){ + length = len; + dataList = new OperateData[len]; + attrList = new OperateDataAttr[len]; + localVarList = new OperateDataLocalVar[len]; + fieldList = new OperateDataField[len]; + arrayList = new OperateDataArrayItem[len]; + keyValueList = new OperateDataKeyValue[len]; + callResultList = new CallResult[len]; + environmentList = new RunEnvironment[len]; + contextList = new InstructionSetContext[len]; + for(int i=0;i aParent,ExpressLoader aExpressLoader,boolean aIsSupportDynamicFieldName){ + InstructionSetContext result = null; + if(contextPoint < length){ + result = contextList[contextPoint]; + result.initial(aIsExpandToParent, aRunner, aParent, aExpressLoader, aIsSupportDynamicFieldName); + contextPoint = contextPoint + 1; + }else{ + result = new InstructionSetContext(aIsExpandToParent, aRunner, aParent, aExpressLoader, aIsSupportDynamicFieldName); + } + return result; + } + public RunEnvironment fetRunEnvironment(InstructionSet aInstructionSet,InstructionSetContext aContext,boolean aIsTrace){ + RunEnvironment result = null; + if(environmentPoint < length){ + result = environmentList[environmentPoint]; + result.initial(aInstructionSet, aContext, aIsTrace); + environmentPoint = environmentPoint + 1; + }else{ + result = new RunEnvironment(aInstructionSet, aContext, aIsTrace); + } + return result; + } + public CallResult fetchCallResult(Object aReturnValue,boolean aIsExit){ + CallResult result = null; + if(callResultPoint < length){ + result = callResultList[callResultPoint]; + result.initial(aReturnValue,aIsExit); + callResultPoint = callResultPoint + 1; + }else{ + result = new CallResult(aReturnValue,aIsExit); + } + return result; + } + public OperateData fetchOperateData(Object obj, Class aType){ + OperateData result = null; + if(dataPoint < length){ + result = dataList[dataPoint]; + result.initial(obj, aType); + dataPoint = dataPoint + 1; + }else{ + result = new OperateData(obj,aType); + } + return result; + } + public OperateDataAttr fetchOperateDataAttr(String name,Class aType){ + OperateDataAttr result = null; + if(attrPoint < length){ + result = attrList[attrPoint]; + result.initialDataAttr(name, aType); + attrPoint = attrPoint + 1; + }else{ + result = new OperateDataAttr(name,aType); + } + return result; + } + + public OperateDataLocalVar fetchOperateDataLocalVar(String name,Class aType){ + OperateDataLocalVar result = null; + if(localVarPoint < length){ + result = localVarList[localVarPoint]; + result.initialDataLocalVar(name, aType); + localVarPoint = localVarPoint + 1; + }else{ + result = new OperateDataLocalVar(name,aType); + } + return result; + } + public OperateDataField fetchOperateDataField(Object aFieldObject,String aFieldName){ + OperateDataField result = null; + if(fieldPoint < length){ + result = fieldList[fieldPoint]; + result.initialDataField(aFieldObject,aFieldName); + fieldPoint = fieldPoint + 1; + }else{ + result = new OperateDataField(aFieldObject,aFieldName); + } + return result; + } + + public OperateDataArrayItem fetchOperateDataArrayItem(OperateData aArrayObject,int aIndex){ + OperateDataArrayItem result = null; + if(arrayPoint < length){ + result = arrayList[arrayPoint]; + result.initialDataArrayItem(aArrayObject,aIndex); + arrayPoint = arrayPoint + 1; + }else{ + result = new OperateDataArrayItem(aArrayObject,aIndex); + } + return result; + } + public OperateDataKeyValue fetchOperateDataKeyValue(OperateData aKey, OperateData aValue){ + OperateDataKeyValue result = null; + if(this.keyValuePoint < length){ + result = this.keyValueList[keyValuePoint]; + result.initialDataKeyValue(aKey,aValue); + keyValuePoint = keyValuePoint + 1; + }else{ + result = new OperateDataKeyValue(aKey,aValue); + } + return result; + } + + public long getFetchCount() { + return 0; + } + + } diff --git a/src/main/java/com/ql/util/express/instruction/OperateDataCacheImpl4Orig.java b/src/main/java/com/ql/util/express/instruction/OperateDataCacheImpl4Orig.java new file mode 100644 index 0000000000000000000000000000000000000000..7b62002ee29ac6b8f14eff4d688b9b121b301bc0 --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/OperateDataCacheImpl4Orig.java @@ -0,0 +1,56 @@ +package com.ql.util.express.instruction; + +import com.ql.util.express.CallResult; +import com.ql.util.express.ExpressLoader; +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.IExpressContext; +import com.ql.util.express.InstructionSet; +import com.ql.util.express.InstructionSetContext; +import com.ql.util.express.OperateData; +import com.ql.util.express.RunEnvironment; +import com.ql.util.express.instruction.opdata.OperateDataArrayItem; +import com.ql.util.express.instruction.opdata.OperateDataAttr; +import com.ql.util.express.instruction.opdata.OperateDataField; +import com.ql.util.express.instruction.opdata.OperateDataKeyValue; +import com.ql.util.express.instruction.opdata.OperateDataLocalVar; + + +class OperateDataCacheImpl4Orig implements IOperateDataCache { + + public OperateData fetchOperateData(Object obj, Class aType) { + return new OperateData(obj,aType); + } + public OperateDataAttr fetchOperateDataAttr(String name, Class aType) { + return new OperateDataAttr(name, aType); + } + public OperateDataLocalVar fetchOperateDataLocalVar(String name, Class aType) { + return new OperateDataLocalVar(name, aType); + } + public OperateDataField fetchOperateDataField(Object aFieldObject,String aFieldName){ + return new OperateDataField(aFieldObject, aFieldName); + } + public OperateDataArrayItem fetchOperateDataArrayItem(OperateData aArrayObject,int aIndex){ + return new OperateDataArrayItem(aArrayObject, aIndex); + } + public OperateDataKeyValue fetchOperateDataKeyValue(OperateData aKey, OperateData aValue){ + return new OperateDataKeyValue(aKey, aValue); + } + + public RunEnvironment fetRunEnvironment(InstructionSet aInstructionSet,InstructionSetContext aContext,boolean aIsTrace){ + return new RunEnvironment(aInstructionSet, aContext, aIsTrace); + } + public CallResult fetchCallResult(Object aReturnValue,boolean aIsExit){ + return new CallResult(aReturnValue, aIsExit); + } + public InstructionSetContext fetchInstructionSetContext(boolean aIsExpandToParent,ExpressRunner aRunner,IExpressContext aParent,ExpressLoader aExpressLoader,boolean aIsSupportDynamicFieldName){ + return new InstructionSetContext(aIsExpandToParent, aRunner, aParent, aExpressLoader, aIsSupportDynamicFieldName); + } + + public void resetCache(){ + + } + public long getFetchCount(){ + return 0; + } + +} diff --git a/src/main/java/com/ql/util/express/instruction/OperateDataCacheManager.java b/src/main/java/com/ql/util/express/instruction/OperateDataCacheManager.java new file mode 100644 index 0000000000000000000000000000000000000000..64e2588fae48e6a466f1ed7a75d3db07c100b6bf --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/OperateDataCacheManager.java @@ -0,0 +1,93 @@ +package com.ql.util.express.instruction; + +import java.util.Stack; + +import com.ql.util.express.CallResult; +import com.ql.util.express.ExpressLoader; +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.IExpressContext; +import com.ql.util.express.InstructionSet; +import com.ql.util.express.InstructionSetContext; +import com.ql.util.express.OperateData; +import com.ql.util.express.RunEnvironment; +import com.ql.util.express.instruction.opdata.OperateDataArrayItem; +import com.ql.util.express.instruction.opdata.OperateDataAttr; +import com.ql.util.express.instruction.opdata.OperateDataField; +import com.ql.util.express.instruction.opdata.OperateDataKeyValue; +import com.ql.util.express.instruction.opdata.OperateDataLocalVar; + + +public class OperateDataCacheManager { + + private static ThreadLocal m_OperateDataObjectCache = new ThreadLocal(){ + protected RunnerDataCache initialValue() { + return new RunnerDataCache(); + } + }; + public static void push(ExpressRunner aRunner){ + m_OperateDataObjectCache.get().push(aRunner); + } + public static IOperateDataCache getOperateDataCache(){ + return m_OperateDataObjectCache.get().cache; + } + public static OperateData fetchOperateData(Object obj, Class aType) { + return getOperateDataCache().fetchOperateData(obj, aType); + } + public static OperateDataAttr fetchOperateDataAttr(String name, Class aType) { + return getOperateDataCache().fetchOperateDataAttr(name, aType); + } + public static OperateDataLocalVar fetchOperateDataLocalVar(String name, Class aType) { + return getOperateDataCache().fetchOperateDataLocalVar(name, aType); + } + public static OperateDataField fetchOperateDataField(Object aFieldObject,String aFieldName){ + return getOperateDataCache().fetchOperateDataField(aFieldObject, aFieldName); + } + public static OperateDataArrayItem fetchOperateDataArrayItem(OperateData aArrayObject,int aIndex){ + return getOperateDataCache().fetchOperateDataArrayItem(aArrayObject, aIndex); + } + public static OperateDataKeyValue fetchOperateDataKeyValue(OperateData aKey, OperateData aValue){ + return getOperateDataCache().fetchOperateDataKeyValue(aKey, aValue); + } + + public static RunEnvironment fetRunEnvironment(InstructionSet aInstructionSet,InstructionSetContext aContext,boolean aIsTrace){ + return getOperateDataCache().fetRunEnvironment(aInstructionSet, aContext, aIsTrace); + } + public static CallResult fetchCallResult(Object aReturnValue,boolean aIsExit){ + return getOperateDataCache().fetchCallResult(aReturnValue, aIsExit); + } + public static InstructionSetContext fetchInstructionSetContext(boolean aIsExpandToParent,ExpressRunner aRunner,IExpressContext aParent,ExpressLoader aExpressLoader,boolean aIsSupportDynamicFieldName){ + return getOperateDataCache().fetchInstructionSetContext(aIsExpandToParent, aRunner, aParent, aExpressLoader, aIsSupportDynamicFieldName); + } + + public static long getFetchCount(){ + return getOperateDataCache().getFetchCount(); + } + + public static void resetCache(ExpressRunner aRunner){ + getOperateDataCache().resetCache(); + m_OperateDataObjectCache.get().pop(aRunner); + + } + + + +} + +class RunnerDataCache{ + IOperateDataCache cache; + + Stack stack = new Stack(); + + public void push(ExpressRunner aRunner){ + this.cache = aRunner.getOperateDataCache(); + this.stack.push(aRunner); + } + public IOperateDataCache getOperateDataCache(){ + return this.cache; + } + public void pop(ExpressRunner aRunner){ + this.cache = this.stack.pop().getOperateDataCache(); + + } + +} diff --git a/src/main/java/com/ql/util/express/instruction/OperatorInstructionFactory.java b/src/main/java/com/ql/util/express/instruction/OperatorInstructionFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..0f3defb6bdd1c84acc3a0efdac465c7c39796060 --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/OperatorInstructionFactory.java @@ -0,0 +1,52 @@ +package com.ql.util.express.instruction; + +import java.util.Stack; + +import com.ql.util.express.ExportItem; +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.InstructionSet; +import com.ql.util.express.instruction.detail.InstructionGoToWithCondition; +import com.ql.util.express.instruction.detail.InstructionGoToWithNotNull; +import com.ql.util.express.instruction.detail.InstructionOperator; +import com.ql.util.express.instruction.detail.InstructionReturn; +import com.ql.util.express.instruction.op.OperatorBase; +import com.ql.util.express.parse.ExpressNode; + + +class OperatorInstructionFactory extends InstructionFactory{ + public boolean createInstruction(ExpressRunner aCompile,InstructionSet result,Stack forStack, ExpressNode node,boolean isRoot) + throws Exception { + boolean returnVal = false; + ExpressNode[] children = node.getChildren(); + int [] finishPoint = new int[children.length]; + for(int i =0;i < children.length;i++){ + ExpressNode tmpNode = children[i]; + boolean tmpHas = aCompile.createInstructionSetPrivate(result,forStack,tmpNode,false); + returnVal = returnVal || tmpHas; + finishPoint[i] = result.getCurrentPoint(); + } + + if(node.isTypeEqualsOrChild("return")){ + result.addInstruction(new InstructionReturn(children.length > 0)); + }else{ + OperatorBase op = aCompile.getOperatorFactory().newInstance(node); + result.addInstruction(new InstructionOperator(op,children.length)); + if(node.isTypeEqualsOrChild("&&") && aCompile.isShortCircuit()){ + result.insertInstruction(finishPoint[0]+1,new InstructionGoToWithCondition(false,result.getCurrentPoint() - finishPoint[0] + 1,false)); + }else if(node.isTypeEqualsOrChild("||") && aCompile.isShortCircuit()){ + result.insertInstruction(finishPoint[0]+1,new InstructionGoToWithCondition(true,result.getCurrentPoint() - finishPoint[0] + 1,false)); + }else if(node.isTypeEqualsOrChild("nor") ){ + result.insertInstruction(finishPoint[0]+1,new InstructionGoToWithNotNull(result.getCurrentPoint() - finishPoint[0] + 1,false)); + }else if(node.isTypeEqualsOrChild("def") || node.isTypeEqualsOrChild("alias")){ + returnVal = true; + }else if(node.isTypeEqualsOrChild("exportDef")){ + //添加对外的变量声明 + result.addExportDef(new ExportItem(children[1].toString(),ExportItem.TYPE_DEF,"还没有实现")); + }else if(node.isTypeEqualsOrChild("exportAlias")){ + result.addExportDef(new ExportItem(children[0].toString(),ExportItem.TYPE_ALIAS,"还没有实现")); + } + } + return returnVal; + } +} + diff --git a/src/main/java/com/ql/util/express/instruction/detail/Instruction.java b/src/main/java/com/ql/util/express/instruction/detail/Instruction.java new file mode 100644 index 0000000000000000000000000000000000000000..d1bbab42856c532a5598f103e91196936b41b29d --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/detail/Instruction.java @@ -0,0 +1,23 @@ +package com.ql.util.express.instruction.detail; + +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import com.ql.util.express.RunEnvironment; + + +public abstract class Instruction implements java.io.Serializable { + + private static final long serialVersionUID = 1361458333068300443L; + protected static transient Log staticLog = LogFactory.getLog(Instruction.class); + protected static transient Log log = staticLog; + public void setLog(Log aLog) { + if (aLog != null) { + this.log = aLog; + } + } + public abstract void execute(RunEnvironment environment, List errorList) + throws Exception; +} diff --git a/src/main/java/com/ql/util/express/instruction/detail/InstructionCallMacro.java b/src/main/java/com/ql/util/express/instruction/detail/InstructionCallMacro.java new file mode 100644 index 0000000000000000000000000000000000000000..b4c51cb68a79d84bb045d61f75fc27aef3c33b04 --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/detail/InstructionCallMacro.java @@ -0,0 +1,49 @@ +package com.ql.util.express.instruction.detail; + +import java.util.List; + +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.RunEnvironment; +import com.ql.util.express.instruction.OperateDataCacheManager; + + +public class InstructionCallMacro extends Instruction{ + private static final long serialVersionUID = -5760553701305043649L; + String name; + public InstructionCallMacro(String aName){ + this.name = aName; + } + + public void execute(RunEnvironment environment,List errorList)throws Exception{ + if(environment.isTrace()&&log.isDebugEnabled()){ + log.debug(this); + } + + InstructionSetContext context = environment.getContext(); + + Object functionSet = context.getSymbol(this.name); + + Object result =InstructionSetRunner.execute( + context.getExpressRunner(), + (InstructionSet)functionSet, + context.getExpressLoader(), + context, + errorList, + environment.isTrace(), + false,false,this.log, + environment.getContext().isSupportDynamicFieldName()); + if(result instanceof OperateData){ + environment.push((OperateData)result); + }else{ + environment.push(OperateDataCacheManager.fetchOperateData(result,null)); + } + + environment.programPointAddOne(); + } + public String toString(){ + return "call macro " + this.name ; + } + } diff --git a/src/main/java/com/ql/util/express/instruction/detail/InstructionCallSelfDefineFunction.java b/src/main/java/com/ql/util/express/instruction/detail/InstructionCallSelfDefineFunction.java new file mode 100644 index 0000000000000000000000000000000000000000..0fa9335f1a2a4224bb489c12cc3f5de3cc1d2f5e --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/detail/InstructionCallSelfDefineFunction.java @@ -0,0 +1,91 @@ +package com.ql.util.express.instruction.detail; + +import java.util.List; + +import org.apache.commons.logging.Log; + +import com.ql.util.express.ArraySwap; +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.RunEnvironment; +import com.ql.util.express.instruction.OperateDataCacheManager; +import com.ql.util.express.instruction.opdata.OperateDataAttr; +import com.ql.util.express.instruction.opdata.OperateDataLocalVar; + +public class InstructionCallSelfDefineFunction extends Instruction{ + private static final long serialVersionUID = 8315682251443515151L; + String functionName; + int opDataNumber; + public InstructionCallSelfDefineFunction(String name,int aOpDataNumber){ + this.functionName = name; + this.opDataNumber =aOpDataNumber; + } + + public String getFunctionName() { + return functionName; + } + + public int getOpDataNumber() { + return opDataNumber; + } + + public void execute(RunEnvironment environment, List errorList) + throws Exception { + ArraySwap parameters = environment.popArray( + environment.getContext(), this.opDataNumber); + if (environment.isTrace() && log.isDebugEnabled()) { + String str = this.functionName + "("; + OperateData p; + for (int i = 0; i < parameters.length; i++) { + p = parameters.get(i); + if (i > 0) { + str = str + ","; + } + if (p instanceof OperateDataAttr) { + str = str + + p + + ":" + + p.getObject(environment + .getContext()); + } else { + str = str + p; + } + } + str = str + ")"; + log.debug(str); + } + + Object function = environment.getContext().getSymbol(functionName); + if (function == null || function instanceof InstructionSet == false) { + throw new Exception("在Runner的操作符定义和自定义函数中都没有找到\"" + + this.functionName + "\"的定义"); + } + InstructionSet functionSet = (InstructionSet)function; + OperateData result = InstructionCallSelfDefineFunction + .executeSelfFunction(environment, functionSet, parameters, + errorList, this.log); + environment.push(result); + environment.programPointAddOne(); + } + public static OperateData executeSelfFunction(RunEnvironment environment,InstructionSet functionSet, + ArraySwap parameters,List errorList,Log log)throws Exception{ + InstructionSetContext context = OperateDataCacheManager.fetchInstructionSetContext ( + true,environment.getContext().getExpressRunner(),environment.getContext(),environment.getContext().getExpressLoader(),environment.getContext().isSupportDynamicFieldName()); + OperateDataLocalVar[] vars = functionSet.getParameters(); + for(int i=0;i errorList)throws Exception{ + //目前的模式,不需要执行任何操作 + if(environment.isTrace() && log.isDebugEnabled()){ + log.debug(this); + } + environment.clearDataStack(); + environment.programPointAddOne(); + } + public String toString(){ + return "clearDataStack"; + } +} + diff --git a/src/main/java/com/ql/util/express/instruction/detail/InstructionCloseNewArea.java b/src/main/java/com/ql/util/express/instruction/detail/InstructionCloseNewArea.java new file mode 100644 index 0000000000000000000000000000000000000000..aeda1d7e5370886b0ed4fc7ac7856ba50b1d5b6b --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/detail/InstructionCloseNewArea.java @@ -0,0 +1,21 @@ +package com.ql.util.express.instruction.detail; + +import java.util.List; + +import com.ql.util.express.InstructionSetContext; +import com.ql.util.express.RunEnvironment; + +public class InstructionCloseNewArea extends Instruction{ + private static final long serialVersionUID = -996832248972683705L; + public void execute(RunEnvironment environment,List errorList)throws Exception{ + //目前的模式,不需要执行任何操作 + if(environment.isTrace() && log.isDebugEnabled()){ + log.debug(this); + } + environment.setContext((InstructionSetContext )environment.getContext().getParent()); + environment.programPointAddOne(); + } + public String toString(){ + return "closeNewArea"; + } +} diff --git a/src/main/java/com/ql/util/express/instruction/detail/InstructionConstData.java b/src/main/java/com/ql/util/express/instruction/detail/InstructionConstData.java new file mode 100644 index 0000000000000000000000000000000000000000..df306890e0c35763e980976cc17be3100c8ad8b7 --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/detail/InstructionConstData.java @@ -0,0 +1,40 @@ +package com.ql.util.express.instruction.detail; + +import java.util.List; + +import com.ql.util.express.OperateData; +import com.ql.util.express.RunEnvironment; +import com.ql.util.express.instruction.opdata.OperateDataAttr; + +public class InstructionConstData extends Instruction { + private static final long serialVersionUID = 745531116947232321L; + OperateData operateData; + + public InstructionConstData(OperateData data) { + this.operateData = data; + } + public OperateData getOperateData(){ + return this.operateData; + } + public void execute(RunEnvironment environment, List errorList) + throws Exception { + if (environment.isTrace() && log.isDebugEnabled()) { + if (this.operateData instanceof OperateDataAttr) { + log.debug(this + ":" + + this.operateData.getObject(environment.getContext())); + } else { + log.debug(this); + } + } + environment.push(this.operateData); + environment.programPointAddOne(); + } + public String toString() { + if (this.operateData instanceof OperateDataAttr) { + return "LoadData attr:" + this.operateData.toString(); + } else { + return "LoadData " + this.operateData.toString(); + } + } + +} diff --git a/src/main/java/com/ql/util/express/instruction/detail/InstructionGoTo.java b/src/main/java/com/ql/util/express/instruction/detail/InstructionGoTo.java new file mode 100644 index 0000000000000000000000000000000000000000..2b41c3ff8fb40f0b7df68b16aee67989ae4e9ec4 --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/detail/InstructionGoTo.java @@ -0,0 +1,42 @@ +package com.ql.util.express.instruction.detail; + +import java.util.List; + +import com.ql.util.express.RunEnvironment; + +public class InstructionGoTo extends Instruction{ + private static final long serialVersionUID = 198094562177756098L; + /** + * 跳转指令的偏移量 + */ + int offset; + public String name; + + public InstructionGoTo(int aOffset){ + this.offset = aOffset; + } + + public void execute(RunEnvironment environment,List errorList) throws Exception { + if(environment.isTrace() && log.isDebugEnabled() ){ + log.debug(this); + } + environment.gotoWithOffset(this.offset); + } + public String toString(){ + String result = (this.name ==null?"":this.name +":") + "GoTo "; + if(this.offset >=0){ + result = result +"+"; + } + result = result + this.offset + " "; + return result; + } + + public int getOffset() { + return offset; + } + + public void setOffset(int offset) { + this.offset = offset; + } + +} diff --git a/src/main/java/com/ql/util/express/instruction/detail/InstructionGoToWithCondition.java b/src/main/java/com/ql/util/express/instruction/detail/InstructionGoToWithCondition.java new file mode 100644 index 0000000000000000000000000000000000000000..86ec8c98e4dcd6325f0fed84414cba14d3612663 --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/detail/InstructionGoToWithCondition.java @@ -0,0 +1,90 @@ +package com.ql.util.express.instruction.detail; + +import java.util.List; + +import com.ql.util.express.OperateData; +import com.ql.util.express.RunEnvironment; +import com.ql.util.express.instruction.OperateDataCacheManager; + +public class InstructionGoToWithCondition extends Instruction{ + private static final long serialVersionUID = -4817805156872407837L; + /** + * 跳转指令的偏移量 + */ + int offset; + boolean condition; + boolean isPopStackData; + public InstructionGoToWithCondition(boolean aCondition,int aOffset,boolean aIsPopStackData){ + this.offset = aOffset; + this.condition = aCondition; + this.isPopStackData = aIsPopStackData; + } + + public void execute(RunEnvironment environment,List errorList)throws Exception{ + Object o = null; + if(this.isPopStackData == false){ + o = environment.peek().getObject(environment.getContext()); + if(o == null){ + environment.pop(); + environment.push(OperateDataCacheManager.fetchOperateData(false,boolean.class)); + } + }else{ + o = environment.pop().getObject(environment.getContext()); + } + boolean r = false; + if(o == null){ + r = false; + }else if(o instanceof Boolean){ + r = ((Boolean)o).booleanValue(); + }else{ + throw new Exception("指令错误:" + o + " 不是Boolean"); + } + if (r == this.condition) { + if (environment.isTrace() && log.isDebugEnabled()) { + log.debug("goto +" + this.offset); + } + environment.gotoWithOffset(this.offset); + } else { + if (environment.isTrace() && log.isDebugEnabled()) { + log.debug("programPoint ++ "); + } + environment.programPointAddOne(); + } + } + + + public String toString(){ + String result = "GoToIf[" + this.condition +",isPop=" + this.isPopStackData +"] " ; + if(this.offset >=0){ + result = result +"+"; + } + result = result + this.offset; + return result; + } + + public int getOffset() { + return offset; + } + + public void setOffset(int offset) { + this.offset = offset; + } + + public boolean isCondition() { + return condition; + } + + public void setCondition(boolean condition) { + this.condition = condition; + } + + public boolean isPopStackData() { + return isPopStackData; + } + + public void setPopStackData(boolean isPopStackData) { + this.isPopStackData = isPopStackData; + } + + +} diff --git a/src/main/java/com/ql/util/express/instruction/detail/InstructionGoToWithNotNull.java b/src/main/java/com/ql/util/express/instruction/detail/InstructionGoToWithNotNull.java new file mode 100644 index 0000000000000000000000000000000000000000..c9f4826c192a8419766ad23c52c22743e31b5c0c --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/detail/InstructionGoToWithNotNull.java @@ -0,0 +1,66 @@ +package com.ql.util.express.instruction.detail; + +import java.util.List; + +import com.ql.util.express.RunEnvironment; + +public class InstructionGoToWithNotNull extends Instruction{ + private static final long serialVersionUID = -2314675800146495935L; + /** + * 跳转指令的偏移量 + */ + int offset; + boolean isPopStackData; + public InstructionGoToWithNotNull(int aOffset,boolean aIsPopStackData){ + this.offset = aOffset; + this.isPopStackData = aIsPopStackData; + } + + public void execute(RunEnvironment environment,List errorList)throws Exception{ + Object o = null; + if(this.isPopStackData == false){ + o = environment.peek().getObject(environment.getContext()); + }else{ + o = environment.pop().getObject(environment.getContext()); + } + if (o != null) { + if (environment.isTrace() && log.isDebugEnabled()) { + log.debug("goto +" + this.offset); + } + environment.gotoWithOffset(this.offset); + } else { + if (environment.isTrace() && log.isDebugEnabled()) { + log.debug("programPoint ++ "); + } + environment.programPointAddOne(); + } + } + + + public String toString(){ + String result = "GoToIf[NOTNULL,isPop=" + this.isPopStackData +"] " ; + if(this.offset >=0){ + result = result +"+"; + } + result = result + this.offset; + return result; + } + + public int getOffset() { + return offset; + } + + public void setOffset(int offset) { + this.offset = offset; + } + + public boolean isPopStackData() { + return isPopStackData; + } + + public void setPopStackData(boolean isPopStackData) { + this.isPopStackData = isPopStackData; + } + + +} diff --git a/src/main/java/com/ql/util/express/instruction/detail/InstructionLoadAttr.java b/src/main/java/com/ql/util/express/instruction/detail/InstructionLoadAttr.java new file mode 100644 index 0000000000000000000000000000000000000000..8c09faa4d35cd5609132ed2008259c11b8e46c70 --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/detail/InstructionLoadAttr.java @@ -0,0 +1,40 @@ +package com.ql.util.express.instruction.detail; + +import java.util.List; + +import com.ql.util.express.InstructionSet; +import com.ql.util.express.RunEnvironment; +import com.ql.util.express.instruction.opdata.OperateDataAttr; + +public class InstructionLoadAttr extends Instruction{ + private static final long serialVersionUID = -2761666977949467250L; + String attrName; + public InstructionLoadAttr(String aName){ + this.attrName = aName; + } + public String getAttrName(){ + return this.attrName; + } + public void execute(RunEnvironment environment,List errorList)throws Exception{ + Object o = environment.getContext().getSymbol(this.attrName); + if(o != null && o instanceof InstructionSet){//是函数,则执行 + if(environment.isTrace() && log.isDebugEnabled()){ + log.debug("指令转换: LoadAttr -- >CallMacro "); + } + InstructionCallMacro macro = new InstructionCallMacro(this.attrName); + macro.setLog(this.log); + macro.execute(environment, errorList); + //注意,此处不能在增加指令,因为在InstructionCallMacro已经调用 environment.programPointAddOne(); + }else{ + if(environment.isTrace() && log.isDebugEnabled()){ + log.debug(this +":" + ((OperateDataAttr)o).getObject(environment.getContext())); + } + environment.push((OperateDataAttr)o); + environment.programPointAddOne(); + } + } + + public String toString(){ + return "LoadAttr:" +this.attrName; + } +} diff --git a/src/main/java/com/ql/util/express/instruction/detail/InstructionNewVirClass.java b/src/main/java/com/ql/util/express/instruction/detail/InstructionNewVirClass.java new file mode 100644 index 0000000000000000000000000000000000000000..9502c742d2403845745183624035cb07f6c9246a --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/detail/InstructionNewVirClass.java @@ -0,0 +1,63 @@ +package com.ql.util.express.instruction.detail; + +import java.util.List; + +import com.ql.util.express.ArraySwap; +import com.ql.util.express.OperateData; +import com.ql.util.express.RunEnvironment; +import com.ql.util.express.instruction.opdata.OperateDataAttr; +import com.ql.util.express.instruction.opdata.OperateDataVirClass; + +public class InstructionNewVirClass extends Instruction { + private static final long serialVersionUID = -4174411242319009814L; + String className; + int opDataNumber; + + public InstructionNewVirClass(String name, int aOpDataNumber) { + this.className = name; + this.opDataNumber = aOpDataNumber; + } + + public void execute(RunEnvironment environment, List errorList) + throws Exception { + ArraySwap parameters = environment.popArray( + environment.getContext(), this.opDataNumber); + if (environment.isTrace() && log.isDebugEnabled()) { + String str = "new VClass("; + OperateData p; + for (int i = 0; i < parameters.length; i++) { + p = parameters.get(i); + if (i > 0) { + str = str + ","; + } + if (p instanceof OperateDataAttr) { + str = str + p + ":" + + p.getObject(environment.getContext()); + } else { + str = str + p; + } + } + str = str + ")"; + log.debug(str); + } + + + //因为会影响堆栈,要先把对象拷贝出来 + OperateData[] list = new OperateData[parameters.length]; + for(int i = 0;i errorList)throws Exception{ + //目前的模式,不需要执行任何操作 + if(environment.isTrace() && log.isDebugEnabled()){ + log.debug(this); + } + InstructionSetContext parentContext = environment.getContext(); + environment.setContext(OperateDataCacheManager.fetchInstructionSetContext ( + true, + parentContext.getExpressRunner(), + parentContext, + parentContext.getExpressLoader(), + parentContext.isSupportDynamicFieldName())); + environment.programPointAddOne(); + } + public String toString(){ + return "openNewArea"; + } +} diff --git a/src/main/java/com/ql/util/express/instruction/detail/InstructionOperator.java b/src/main/java/com/ql/util/express/instruction/detail/InstructionOperator.java new file mode 100644 index 0000000000000000000000000000000000000000..29cb50ec7c174385a77554de2936fb85874820a9 --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/detail/InstructionOperator.java @@ -0,0 +1,52 @@ +package com.ql.util.express.instruction.detail; + +import java.util.List; + +import org.apache.commons.logging.Log; + +import com.ql.util.express.ArraySwap; +import com.ql.util.express.OperateData; +import com.ql.util.express.RunEnvironment; +import com.ql.util.express.instruction.op.OperatorBase; +import com.ql.util.express.instruction.opdata.OperateDataAttr; + +public class InstructionOperator extends Instruction{ + private static final long serialVersionUID = -1217916524030161947L; + OperatorBase operator; + int opDataNumber; + public InstructionOperator(OperatorBase aOperator,int aOpDataNumber){ + this.operator = aOperator; + this.opDataNumber =aOpDataNumber; + } + public OperatorBase getOperator(){ + return this.operator; + } + public void execute(RunEnvironment environment,List errorList) throws Exception{ + ArraySwap parameters = environment.popArray(environment.getContext(),this.opDataNumber); + if(environment.isTrace() && this.log.isDebugEnabled()){ + String str = this.operator.toString() + "("; + OperateData p = null; + for(int i=0;i 0){ + str = str + ","; + } + if(p instanceof OperateDataAttr){ + str = str + p + ":" + p.getObject(environment.getContext()); + }else{ + str = str + p; + } + } + str = str + ")"; + this.log.debug(str); + } + + OperateData result = this.operator.execute(environment.getContext(),parameters, errorList); + environment.push(result); + environment.programPointAddOne(); + } + public String toString(){ + String result = "OP : " + this.operator.toString() + " OPNUMBER[" + this.opDataNumber +"]"; + return result; + } +} diff --git a/src/main/java/com/ql/util/express/instruction/detail/InstructionReturn.java b/src/main/java/com/ql/util/express/instruction/detail/InstructionReturn.java new file mode 100644 index 0000000000000000000000000000000000000000..fa028863c08d37eea7d6bfc156970161b7094254 --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/detail/InstructionReturn.java @@ -0,0 +1,32 @@ +package com.ql.util.express.instruction.detail; + +import java.util.List; + +import com.ql.util.express.RunEnvironment; + +public class InstructionReturn extends Instruction{ + private static final long serialVersionUID = -4991998239277488949L; + boolean haveReturnValue; + public InstructionReturn(boolean aHaveReturnValue){ + this.haveReturnValue = aHaveReturnValue; + } + public void execute(RunEnvironment environment,List errorList)throws Exception{ + //目前的模式,不需要执行任何操作 + if(environment.isTrace() && log.isDebugEnabled()){ + log.debug(this); + } + if(this.haveReturnValue == true){ + environment.quitExpress(environment.pop().getObject(environment.getContext())); + }else{ + environment.quitExpress(); + } + environment.gotoLastWhenReturn(); + } + public String toString(){ + if(this.haveReturnValue){ + return "return [value]"; + }else{ + return "return"; + } + } +} diff --git a/src/main/java/com/ql/util/express/instruction/op/CanClone.java b/src/main/java/com/ql/util/express/instruction/op/CanClone.java new file mode 100644 index 0000000000000000000000000000000000000000..74e5e85eddb040c0c016bf21a82e175ed25eba7b --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/op/CanClone.java @@ -0,0 +1,5 @@ +package com.ql.util.express.instruction.op; + +public interface CanClone { + public OperatorBase cloneMe(String name,String errorInfo) throws Exception; +} diff --git a/src/main/java/com/ql/util/express/instruction/op/OperatorAdd.java b/src/main/java/com/ql/util/express/instruction/op/OperatorAdd.java new file mode 100644 index 0000000000000000000000000000000000000000..24b9a62e3309a41140df02867b06c1497be165a6 --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/op/OperatorAdd.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 OperatorAdd extends Operator { + public OperatorAdd(String name) { + this.name = name; + } + public OperatorAdd(String aAliasName, String aName, String aErrorInfo) { + this.name = aName; + this.aliasName = aAliasName; + this.errorInfo = aErrorInfo; + } + public Object executeInner(Object[] list) throws Exception { + return OperatorOfNumber.add(list[0], list[1],this.isPrecise); + } +} diff --git a/src/main/java/com/ql/util/express/instruction/op/OperatorAlias.java b/src/main/java/com/ql/util/express/instruction/op/OperatorAlias.java new file mode 100644 index 0000000000000000000000000000000000000000..ac6a767bf8936d8537bba742c8f6dfca02849cd8 --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/op/OperatorAlias.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 OperatorAlias extends OperatorBase { + public OperatorAlias(String aName) { + this.name = aName; + } + public OperatorAlias(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/OperatorAnd.java b/src/main/java/com/ql/util/express/instruction/op/OperatorAnd.java new file mode 100644 index 0000000000000000000000000000000000000000..22b26d675f746081bcfc293d9b31b17230f898b3 --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/op/OperatorAnd.java @@ -0,0 +1,49 @@ +package com.ql.util.express.instruction.op; + +import com.ql.util.express.Operator; + +/** + * 处理 And,Or,&&,||操作 + */ + +public class OperatorAnd extends Operator { + public OperatorAnd(String name) { + this.name = name; + } + public OperatorAnd(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/OperatorAnonymousNewArray.java b/src/main/java/com/ql/util/express/instruction/op/OperatorAnonymousNewArray.java new file mode 100644 index 0000000000000000000000000000000000000000..7e9df1b3d58bef562c809cf4aa3fe5407a0ad43e --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/op/OperatorAnonymousNewArray.java @@ -0,0 +1,55 @@ +package com.ql.util.express.instruction.op; + +import java.lang.reflect.Array; + +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 OperatorAnonymousNewArray extends OperatorBase { + public OperatorAnonymousNewArray(String aName) { + this.name = aName; + } + public OperatorAnonymousNewArray(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 type = this.findArrayClassType(context,list); + type = ExpressUtil.getSimpleDataType(type); + int[] dims = new int[1]; + dims[0]= list.length; + Object data = Array.newInstance(type,dims); + for(int i=0;ifindArrayClassType(InstructionSetContext context, ArraySwap list) throws Exception { + Class type = null; + for(int i=0;i type1 = list.get(i).getType(context); + if(type1==null){ + //doNothing + }else if(type==null){ + //第一次赋值 + type = type1; + }else if(type1==type || type.isAssignableFrom(type1)){//type1是type的子类 + //doNothing + }else if(type1.isAssignableFrom(type)){ + //寻找更基础的类 + type = type1 ; + }else{ + type = Object.class; + } + } + if(type==null) type = Object.class;//参数全部为null的情况 + return type; + } +} diff --git a/src/main/java/com/ql/util/express/instruction/op/OperatorAnonymousNewList.java b/src/main/java/com/ql/util/express/instruction/op/OperatorAnonymousNewList.java new file mode 100644 index 0000000000000000000000000000000000000000..8c00cc6b58fd2336376fddd8f9ad7dc9c15e456e --- /dev/null +++ b/src/main/java/com/ql/util/express/instruction/op/OperatorAnonymousNewList.java @@ -0,0 +1,28 @@ +package com.ql.util.express.instruction.op; + +import java.util.ArrayList; +import java.util.List; + +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; + +public class OperatorAnonymousNewList extends OperatorBase { + public OperatorAnonymousNewList(String aName) { + this.name = aName; + } + public OperatorAnonymousNewList(String aAliasName, String aName, String aErrorInfo) { + this.name = aName; + this.aliasName = aAliasName; + this.errorInfo = aErrorInfo; + } + + public OperateData executeInner(InstructionSetContext context, ArraySwap list) throws Exception { + List result = new ArrayList(); + for(int i=0;i result = new HashMap(); + for(int i=0;iTitle:Operator

+ *

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 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 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 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 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 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 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 expressContext = new IExpressContext () { + Map map = new HashMap(); + public Object put(String name, Object object) { + return map.put(name, object); + } + public Object get(Object key) { + return map.get(key); + } + }; + + Map map = new HashMap(); + map.put("key1", 1); + expressContext.put("map", map); + + String expressionstr = "map.key1"; + ExpressRunner runner = new ExpressRunner(false,true); + Object r =runner.execute(expressionstr, expressContext, null, + true, true); + Assert.assertTrue("Map读取错误", r.toString().equalsIgnoreCase("1")); + + } +} diff --git a/src/test/java/com/ql/util/express/test/TestMethodParams.java b/src/test/java/com/ql/util/express/test/TestMethodParams.java new file mode 100644 index 0000000000000000000000000000000000000000..ed392aaf40b377e5d95d7b147e4be1404ca88452 --- /dev/null +++ b/src/test/java/com/ql/util/express/test/TestMethodParams.java @@ -0,0 +1,183 @@ +package com.ql.util.express.test; + +import com.ql.util.express.DefaultContext; +import com.ql.util.express.DynamicParamsUtil; +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.IExpressContext; +import com.ql.util.express.example.operator.ApproveOperator; +import org.junit.Test; + +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * tianqiao + * 2016-09-12 + */ +public class TestMethodParams { + + @Test + public void testMethodDynamicDemo() throws Exception { + ExpressRunner runner = new ExpressRunner(); + IExpressContext expressContext = new DefaultContext(); + + //(1)默认的不定参数可以使用数组来代替 + Object r = runner.execute("a = new com.ql.util.express.test.TestMethodParams();a.getTemplate([11,'22',33L,true])", expressContext, null,false, false); + System.out.println(r); + //(2)目前只支持只有Object[]一个参数的这种情况 + Object r2 = runner.execute("a = new com.ql.util.express.test.TestMethodParams();a.getTemplate(11,'22',33L,true)", expressContext, null,false, false); + System.out.println(r2); + } + + @Test + public void testDynamicDemo() 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; + } + + + + + + + + //等价于Integer[] params + public Integer integerArrayInvoke(Integer... params) throws Exception{ + if(params==null) + { + return 0; + } + Integer result = 0; + for(Integer obj:params){ + if(obj!=null) + result = result+obj; + } + System.out.println(result); + return result; + } + + //等价于Object[] params + public Object objectArrayInvoke(Object... params) throws Exception{ + if(params==null) + { + return ""; + } + String result = ""; + for(Object obj:params){ + if(obj!=null) + result = result+obj.toString()+","; + } + System.out.println(result); + return result; + } + + //等价于Integer[] params,重载objectArrayInvoke + public Object objectArrayInvoke(Integer... params) throws Exception{ + return this.integerArrayInvoke(params); + } + + //带同步的不定参数 + public Object objectArrayInvokeWithHead(String head,Integer... params) throws Exception{ + return head+this.integerArrayInvoke(params); + } + + @Test + public void testMethodArrayParamType() throws Exception { + + Class longClasss = Long.class; + Class numberClasss = Number.class; + Class stringClass = String.class; + Class objectClass = Object.class; + + assert(numberClasss.isAssignableFrom(longClasss)); + assert(objectClass.isAssignableFrom(numberClasss)); + assert(objectClass.isAssignableFrom(stringClass)); + + ExpressRunner runner = new ExpressRunner(); + IExpressContext expressContext = new DefaultContext(); + runner.addFunctionOfServiceMethod("integerArrayInvoke", this, "integerArrayInvoke", new Class[]{Integer[].class}, null); + runner.addFunctionOfServiceMethod("objectArrayInvokeWithHead", this, "objectArrayInvokeWithHead", new Class[]{String.class,Integer[].class}, null); + runner.addFunctionOfServiceMethod("objectArrayInvoke", this, "objectArrayInvoke", new Class[]{Object[].class}, null); + runner.addFunctionOfServiceMethod("objectArrayInvoke_Integer", this, "objectArrayInvoke", new Class[]{Integer[].class}, null); + + testInvoke("integerArrayInvoke([1,2,3,4])","10",runner,expressContext); + //null测试 + testInvoke("integerArrayInvoke(null)","0",runner,expressContext); + testInvoke("integerArrayInvoke([null,1,2,3,null,4])","10",runner,expressContext); + testInvoke("integerArrayInvoke([null,null])","0",runner,expressContext); + testInvoke("objectArrayInvoke([null,null])","",runner,expressContext); + + //重载测试 + testInvoke("objectArrayInvoke([1,2,3,null,4])","1,2,3,4,",runner,expressContext); + testInvoke("objectArrayInvoke_Integer([1,2,3,null,4])","10",runner,expressContext); + //需要把数组统一成Object + testInvoke("objectArrayInvoke(['1',2,3,null,4])","1,2,3,4,",runner,expressContext); + + //带有head + testInvoke("objectArrayInvokeWithHead('hello:',[1,2,3,null,4])","hello:10",runner,expressContext); + } + + + + @Test + public void testDynamicParams() throws Exception { + + DynamicParamsUtil.supportDynamicParams = true; + + + ExpressRunner runner = new ExpressRunner(); + IExpressContext expressContext = new DefaultContext(); + runner.addFunctionOfServiceMethod("integerArrayInvoke", this, "integerArrayInvoke", new Class[]{Integer[].class}, null); + runner.addFunctionOfServiceMethod("objectArrayInvoke", this, "objectArrayInvoke", new Class[]{Object[].class}, null); + runner.addFunctionOfServiceMethod("objectArrayInvoke_Integer", this, "objectArrayInvoke", new Class[]{Integer[].class}, null); + runner.addFunctionOfServiceMethod("objectArrayInvokeWithHead", this, "objectArrayInvokeWithHead", new Class[]{String.class,Integer[].class}, null); + + testInvoke("integerArrayInvoke()","0",runner,expressContext); + testInvoke("integerArrayInvoke(null)","0",runner,expressContext); + testInvoke("integerArrayInvoke(1)","1",runner,expressContext); + testInvoke("integerArrayInvoke(1,2,3,4)","10",runner,expressContext); + //null测试 + testInvoke("integerArrayInvoke(null,1,2,3,null,4)","10",runner,expressContext); + testInvoke("integerArrayInvoke(null,null)","0",runner,expressContext); + testInvoke("objectArrayInvoke(null,null)","",runner,expressContext); + + //重载测试 + testInvoke("objectArrayInvoke()","",runner,expressContext); + testInvoke("objectArrayInvoke(null)","",runner,expressContext); + testInvoke("objectArrayInvoke(null,1,2,3,4)","1,2,3,4,",runner,expressContext); + testInvoke("objectArrayInvoke(1,2,3,null,4)","1,2,3,4,",runner,expressContext); + testInvoke("objectArrayInvoke_Integer(1,2,3,null,4)","10",runner,expressContext); + //需要把数组统一成Object + testInvoke("objectArrayInvoke('1',2,3,null,4)","1,2,3,4,",runner,expressContext); + //带有head + testInvoke("objectArrayInvokeWithHead('hello:',1,2,3,null,4)","hello:10",runner,expressContext); + + } + + void testInvoke(String text,String expert,ExpressRunner runner,IExpressContext expressContext) throws Exception { + + Object r = runner.execute(text, expressContext, null,false, false); + assert (r.toString().equals(expert)); + + } + +} diff --git a/src/test/java/com/ql/util/express/test/TestSerializable.java b/src/test/java/com/ql/util/express/test/TestSerializable.java new file mode 100644 index 0000000000000000000000000000000000000000..12e30df6c0feca3f31341ec0d0ab16d3dcec3750 --- /dev/null +++ b/src/test/java/com/ql/util/express/test/TestSerializable.java @@ -0,0 +1,50 @@ +package com.ql.util.express.test; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +import org.junit.Test; + +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.InstructionSet; + +public class TestSerializable { + + @Test + public void testSerializable() throws Exception { + + ExpressRunner runner = new ExpressRunner(); + InstructionSet staff = runner.parseInstructionSet("1+1"); + try { + + ObjectOutputStream out = new ObjectOutputStream( + new FileOutputStream("target/qlcache.dat")); + + out.writeObject(staff); + + out.close(); + + ObjectInputStream in = new ObjectInputStream(new FileInputStream( + "target/qlcache.dat")); + + InstructionSet newStaff = (InstructionSet) in.readObject(); + + in.close(); + + System.out.print(newStaff); + + } + + catch (Exception e) + + { + + e.printStackTrace(); + throw e; + + } + + } +} diff --git a/src/test/java/com/ql/util/express/test/TestSet.java b/src/test/java/com/ql/util/express/test/TestSet.java new file mode 100644 index 0000000000000000000000000000000000000000..8e17a077c551ad12bd0749c8647f83e0b6426a78 --- /dev/null +++ b/src/test/java/com/ql/util/express/test/TestSet.java @@ -0,0 +1,26 @@ +package com.ql.util.express.test; + +import com.ql.util.express.DefaultContext; +import com.ql.util.express.ExpressRunner; +import org.junit.Test; + +/** + * Created by tianqiao on 16/9/13. + */ +public class TestSet { + + @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/src/test/java/com/ql/util/express/test/VarAreaTest.java b/src/test/java/com/ql/util/express/test/VarAreaTest.java new file mode 100644 index 0000000000000000000000000000000000000000..cd9907fe8a2b968429d96d1bf86c3f0c47bceb8a --- /dev/null +++ b/src/test/java/com/ql/util/express/test/VarAreaTest.java @@ -0,0 +1,53 @@ +package com.ql.util.express.test; + +import org.junit.Assert; + +import com.ql.util.express.DefaultContext; +import com.ql.util.express.ExpressRunner; + +public class VarAreaTest { + @org.junit.Test + public void testVarArea1() throws Exception{ + String express = + " qh = 1; " + + "如果 ( false) 则 {" + + " 3 + (3) + (4 + 1)" + + " }否则{" + + " qh = 3;" + + " qh = qh + 100;" + + "}; " + + "qh = qh + 1;"; + ExpressRunner runner = new ExpressRunner(); + DefaultContext context = new DefaultContext(); + runner.addOperatorWithAlias("如果", "if",null); + runner.addOperatorWithAlias("则", "then",null); + runner.addOperatorWithAlias("否则", "else",null); + Object r = runner.execute(express,context, null, false,false); + System.out.println(r); + System.out.println(context); + Assert.assertTrue("变量定义作用域错误", context.get("qh").toString().equals("104")); + + } + @org.junit.Test + public void testVarArea2() throws Exception{ + String express = + " qh = 1; " + + "如果 ( false) 则 {" + + " 3 + (3) + (4 + 1)" + + " }否则{" + + " int qh = 3;" + + " qh = qh + 100;" + + "}; " + + "qh = qh + 1;"; + ExpressRunner runner = new ExpressRunner(); + DefaultContext context = new DefaultContext(); + runner.addOperatorWithAlias("如果", "if",null); + runner.addOperatorWithAlias("则", "then",null); + runner.addOperatorWithAlias("否则", "else",null); + Object r = runner.execute(express,context, null, false,false); + System.out.println(r); + System.out.println(context); + Assert.assertTrue("变量定义作用域错误", context.get("qh").toString().equals("2")); + + } +} diff --git a/src/test/java/com/ql/util/express/test/demo/QLExpressContext.java b/src/test/java/com/ql/util/express/test/demo/QLExpressContext.java new file mode 100644 index 0000000000000000000000000000000000000000..80670054cfb5af2df8431ef6e814f52e53a6113b --- /dev/null +++ b/src/test/java/com/ql/util/express/test/demo/QLExpressContext.java @@ -0,0 +1,50 @@ +package com.ql.util.express.test.demo; + +import java.util.HashMap; +import java.util.Map; +import org.springframework.context.ApplicationContext; + +import com.ql.util.express.IExpressContext; + +@SuppressWarnings("serial") +public class QLExpressContext extends HashMap implements + IExpressContext { + + private ApplicationContext context; + + public QLExpressContext(ApplicationContext aContext) { + this.context = aContext; + } + + public QLExpressContext(Map aProperties, + ApplicationContext aContext) { + super(aProperties); + this.context = aContext; + } + + /** + * 抽象方法:根据名称从属性列表中提取属性值 + */ + public Object get(Object name) { + Object result = null; + 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/demo/QlExpressUtil.java b/src/test/java/com/ql/util/express/test/demo/QlExpressUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..096f5627ea20ea75f27a0daf5d1fa7cd5c6b3778 --- /dev/null +++ b/src/test/java/com/ql/util/express/test/demo/QlExpressUtil.java @@ -0,0 +1,77 @@ +package com.ql.util.express.test.demo; + +import java.util.Map; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.IExpressContext; + +public class QlExpressUtil implements ApplicationContextAware { + + private static ExpressRunner runner; + static { + runner = new ExpressRunner(); + } + private static boolean isInitialRunner = false; + private ApplicationContext applicationContext;// spring上下文 + + /** + * + * @param statement + * 执行语句 + * @param context + * 上下文 + * @throws Exception + */ + @SuppressWarnings("unchecked") + public Object execute(String statement, Map context) + throws Exception { + initRunner(runner); + IExpressContext expressContext = new QLExpressContext(context, + applicationContext); + statement = initStatement(statement); + return runner.execute(statement, expressContext, null, true, false); + } + + /** + * 在此处把一些中文符号替换成英文符号 + * + * @param statement + * @return + */ + private String initStatement(String statement) { + return statement.replace("(", "(").replace(")", ")").replace(";", ";") + .replace(",", ",").replace("“", "\"").replace("”", "\""); + } + + private void initRunner(ExpressRunner runner) { + if (isInitialRunner == true) { + return; + } + synchronized (runner) { + if (isInitialRunner == true) { + return; + } + try { + runner.addFunctionOfServiceMethod("注册用户",applicationContext.getBean("bizLogicBean"), "signUser", new Class[] {String.class}, null); + runner.addFunctionOfServiceMethod("开店",applicationContext.getBean("bizLogicBean"), "openShop", new Class[] {com.ql.util.express.test.demo.biz.UserDO.class}, null); + runner.addFunctionOfServiceMethod("星级自增",applicationContext.getBean("bizLogicBean"), "addScore", new Class[] {com.ql.util.express.test.demo.biz.UserDO.class}, null); + runner.addFunctionOfServiceMethod("店铺升级",applicationContext.getBean("bizLogicBean"), "upgradeShop", new Class[] {com.ql.util.express.test.demo.biz.UserDO.class}, null); + runner.addFunctionOfServiceMethod("店铺营业中",applicationContext.getBean("bizLogicBean"), "isShopOpening", new Class[] {com.ql.util.express.test.demo.biz.UserDO.class}, null); + + } catch (Exception e) { + throw new RuntimeException("初始化失败表达式", e); + } + } + isInitialRunner = true; + } + + public void setApplicationContext(ApplicationContext aContext) + throws BeansException { + applicationContext = aContext; + } + +} diff --git a/src/test/java/com/ql/util/express/test/demo/TestQlExpress.java b/src/test/java/com/ql/util/express/test/demo/TestQlExpress.java new file mode 100644 index 0000000000000000000000000000000000000000..b62981c0c2f5d5994205db22a41c4574fed14fae --- /dev/null +++ b/src/test/java/com/ql/util/express/test/demo/TestQlExpress.java @@ -0,0 +1,69 @@ +package com.ql.util.express.test.demo; + +import java.util.HashMap; +import java.util.Map; + +import org.unitils.UnitilsJUnit4; +import org.unitils.spring.annotation.SpringApplicationContext; +import org.unitils.spring.annotation.SpringBeanByName; + +@SpringApplicationContext("classpath:spring-express-config.xml") +public class TestQlExpress extends UnitilsJUnit4{ + + @SpringBeanByName + QlExpressUtil qlExpressUtil; + + + /** + * 使用qlExpressUtil扩展了QlExpressRunner的expressContext参数, + * 使脚本中可以直接调用spring中的bean + * + * 场景业务逻辑如下: + * ****************************************************************** + * + * 用户qlExpress注册一个账号 + * 用户qlExpress开了个淘宝店 + * 通过自己的苦心经营,星级不断升高,qlExpress不断的期望着能够地店铺升级为商城用户 + * 终于有一天他成功了。 + * + * ****************************************************************** + * @throws Exception + */ + @org.junit.Test + public void testScript() throws Exception{ + + Map context = new HashMap(); + context.put("nick", "qlExpress"); + qlExpressUtil.execute("用户A = bizLogicBean.signUser(nick);" + + "bizLogicBean.openShop(用户A );" + + "for(;; bizLogicBean.isShopOpening(用户A ) && !bizLogicBean.upgradeShop(用户A )){bizLogicBean.addScore(用户A );}", + context); + } + + + /** + * + * 使用预先定义的函数,脚本即逻辑: + * ****************************************************************** + * + * "用户A = 注册用户(nick);" + + * "开店(用户A);" + + * "for(;;店铺营业中(用户A) && !店铺升级(用户A)){星级自增(用户A);} + * + * ****************************************************************** + * @throws Exception + */ + + @org.junit.Test + public void testDeclareMethodScript() throws Exception{ + + Map context = new HashMap(); + context.put("nick", "qlExpress"); + qlExpressUtil.execute("用户A = 注册用户(nick);" + + "开店(用户A);" + + "for(;;店铺营业中(用户A) && !店铺升级(用户A)){星级自增(用户A);}", + context); + } + + +} diff --git a/src/test/java/com/ql/util/express/test/demo/biz/BizLogicBean.java b/src/test/java/com/ql/util/express/test/demo/biz/BizLogicBean.java new file mode 100644 index 0000000000000000000000000000000000000000..98390f9800642daec1af4f61c6eb605633927019 --- /dev/null +++ b/src/test/java/com/ql/util/express/test/demo/biz/BizLogicBean.java @@ -0,0 +1,83 @@ +package com.ql.util.express.test.demo.biz; + +public class BizLogicBean { + + + /** + * 注册新用户 + * @param nick + * @return + */ + public UserDO signUser(String nick){ + UserDO user = new UserDO(); + user.setNick(nick); + user.setScore(0L); + user.setShopOpen(false); + user.setShopType("no_shop"); + System.out.println("创建用户成功:"+user); + return user; + } + /** + * 用户店铺激活 + * @param user + */ + public void openShop(UserDO user){ + user.setShopOpen(true); + user.setShopType("c2c"); + System.out.println("店铺已经激活:"+user); + user.setShopOpen(true); + } + + /** + * 用户店铺关闭 + * @param user + */ + public void closeShop(UserDO user){ + user.setShopOpen(false); + System.out.println("店铺已经关闭:"+user); + user.setShopOpen(false); + } + + /** + * 用户星级+1 + * @param user + */ + public void addScore(UserDO user){ + user.setScore(user.getScore()+1); + System.out.println("用户星级 +1 :"+user); + } + + public boolean isShopOpening(UserDO user){ + if(user.isShopOpen()){ + System.out.println("当前店铺为营业状态."); + return true; + } + System.out.println("当前店铺为关闭状态."); + return false; + } + + /** + * 店铺升级 + * @param user + * @return + */ + public boolean upgradeShop(UserDO user){ + if(user.getShopType().equals("b2c")){ + System.out.println("您已经是B商家,不用升级了."); + return false; + } + if(user.getScore().longValue()>5L){ + user.setShopType("b2c"); + System.out.println("成功升级为B商家:"+user); + return true; + }else{ + System.out.println("需要5星级以上卖家,你现在才"+user.getScore()+"星级,再接再厉哦!"); + return false; + } + } + + public void showShop(UserDO user){ + System.out.println(user); + } + +} diff --git a/src/test/java/com/ql/util/express/test/demo/biz/UserDO.java b/src/test/java/com/ql/util/express/test/demo/biz/UserDO.java new file mode 100644 index 0000000000000000000000000000000000000000..c6f3406a3d974e4c5b374b26281144b41211ddc6 --- /dev/null +++ b/src/test/java/com/ql/util/express/test/demo/biz/UserDO.java @@ -0,0 +1,72 @@ +package com.ql.util.express.test.demo.biz; + +public class UserDO { + + /** + * 用户昵称 + */ + private String nick; + + /** + * 开店状态 + */ + private boolean shopOpen; + + /** + * 星级 + */ + private Long score; + + /** + * 店铺类型:c2c,b2c + */ + private String shopType; + + public String getNick() { + return nick; + } + + public void setNick(String nick) { + this.nick = nick; + } + + public Long getScore() { + return score; + } + + public void setScore(Long score) { + this.score = score; + } + + public boolean isShopOpen() { + return shopOpen; + } + + public void setShopOpen(boolean shopOpen) { + this.shopOpen = shopOpen; + } + + public String getShopType() { + return shopType; + } + + public void setShopType(String shopType) { + this.shopType = shopType; + } + + + public String toString(){ + StringBuffer sb = new StringBuffer("用户信息:"); + sb.append("\t\t昵称: ").append(nick); + if(shopOpen){ + sb.append("\t\t店铺状态: 营业中"); + }else{ + sb.append("\t\t店铺状态: 关闭中"); + } + sb.append("\t\t卖家星级: ").append(score); + sb.append("\t\t店铺类型: ").append(shopType); + return sb.toString(); + } + + +} diff --git a/src/test/java/com/ql/util/express/test/logic/ShortCircuitLogicTest.java b/src/test/java/com/ql/util/express/test/logic/ShortCircuitLogicTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e29313aaf03b86614c2d45ca208b4a155e990b9c --- /dev/null +++ b/src/test/java/com/ql/util/express/test/logic/ShortCircuitLogicTest.java @@ -0,0 +1,86 @@ +package com.ql.util.express.test.logic; + +import java.util.ArrayList; +import java.util.List; + +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 ShortCircuitLogicTest { + + private ExpressRunner runner = new ExpressRunner(); + + public void initial() throws Exception{ + runner.addOperatorWithAlias("小于","<","$1 小于 $2 不满足期望"); + runner.addOperatorWithAlias("大于",">","$1 大于 $2 不满足期望"); + } + + public boolean calculateLogicTest(String expression,IExpressContext expressContext,List errorInfo) throws Exception { + Boolean result = (Boolean)runner.execute(expression, expressContext, errorInfo, true, false); + if(result.booleanValue() == true){ + return true; + } + return false; + } + + /** + * 测试非短路逻辑,并且输出出错信息 + * @throws Exception + */ + @Test + public void testShortCircuit() throws Exception { + runner.setShortCircuit(true); + IExpressContext expressContext = new DefaultContext(); + expressContext.put("违规天数", 100); + expressContext.put("虚假交易扣分", 11); + expressContext.put("VIP", false); + List errorInfo = new ArrayList(); + initial(); + String expression ="2 小于 1 and (违规天数 小于 90 or 虚假交易扣分 小于 12)"; + boolean result = calculateLogicTest(expression, expressContext, errorInfo); + if(result){ + System.out.println("result is success!"); + }else{ + System.out.println("result is fail!"); + for(String error : errorInfo){ + System.out.println(error); + } + } + + } + + /** + * 测试非短路逻辑,并且输出出错信息 + * @throws Exception + */ + @Test + public void testNoShortCircuit() throws Exception { + runner.setShortCircuit(false); + IExpressContext expressContext = new DefaultContext(); + expressContext.put("违规天数", 100); + expressContext.put("虚假交易扣分", 11); + expressContext.put("VIP", false); + List errorInfo = new ArrayList(); + initial(); + String expression ="2 小于 1 and (违规天数 小于 90 or 虚假交易扣分 小于 12)"; + boolean result = calculateLogicTest(expression, expressContext, errorInfo); + if(result){ + System.out.println("result is success!"); + }else{ + System.out.println("result is fail!"); + for(String error : errorInfo){ + System.out.println(error); + } + } + + } + +} diff --git a/src/test/java/com/ql/util/express/test/newmatch/PatternTest.java b/src/test/java/com/ql/util/express/test/newmatch/PatternTest.java new file mode 100644 index 0000000000000000000000000000000000000000..394c61d1e46d4d106a969e5aee232081fb7c93d1 --- /dev/null +++ b/src/test/java/com/ql/util/express/test/newmatch/PatternTest.java @@ -0,0 +1,51 @@ +package com.ql.util.express.test.newmatch; + +import java.util.List; + +import org.junit.Test; + +import com.ql.util.express.match.QLMatchResult; +import com.ql.util.express.match.QLPattern; +import com.ql.util.express.match.QLPatternNode; +import com.ql.util.express.parse.ExpressNode; +import com.ql.util.express.parse.ExpressParse; +import com.ql.util.express.parse.KeyWordDefine4Java; +import com.ql.util.express.parse.NodeTypeManager; +import com.ql.util.express.parse.Word; +import com.ql.util.express.parse.WordSplit; + +public class PatternTest { + + + @Test + public void testMatch() throws Exception{ + String[][] defines = new String[][]{ + // {"EXPRESS","(3-2)*(2-1)"}, + // {"OPDATA","ABC.B"}, + // {"EXPRESS_OP_L1","!ABC"}, + // {"EXPRESS","!!3 * !!4 * 5 + 8 + 7 +9 like ABC"}, + // {"EXPRESS_OP_L5","7+!!3*4 like 9 +!!2*4"}, + // {"SELECT","select TAB.TABLE_NAME + '-ABC',TAB.COL_NAME.B * 100 from A,B"}, + {"EXPRESS_OP_L4","-3*-5"}, + + }; + NodeTypeManager manager = new NodeTypeManager(new KeyWordDefine4Java()); + if( manager.findNodeType("OP_LIST").isContainerChild(manager.findNodeType("*")) ==false){ + throw new Exception("寻找儿子失败"); + } + ExpressParse parse = new ExpressParse(manager,null,false); + for(String[] row : defines){ + Word[] words = WordSplit.parse(manager.splitWord,row[1]); +// System.out.println("单词分解结果:" + WordSplit.getPrintInfo(words,",")); + List tempList = parse.transferWord2ExpressNode(null,words,null,true); + System.out.println("单词分析结果:" + ExpressParse.printInfo(tempList,",")); + QLPatternNode pattern = manager.findNodeType(row[0]).getPatternNode(); + QLMatchResult result =QLPattern.findMatchStatement(manager, pattern, tempList, 0); + if(result == null){ + throw new Exception("没有正确的匹配:" + row[0] + ":" + row[1]); + } + System.out.println(result); + } + + } +} diff --git a/src/test/java/com/ql/util/express/test/newmatch/QLPatternDefineTest.java b/src/test/java/com/ql/util/express/test/newmatch/QLPatternDefineTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b5f4f233258448693f9021ea143f39a945c23bf5 --- /dev/null +++ b/src/test/java/com/ql/util/express/test/newmatch/QLPatternDefineTest.java @@ -0,0 +1,31 @@ +package com.ql.util.express.test.newmatch; + +import org.junit.Test; + +import com.ql.util.express.match.INodeTypeManager; +import com.ql.util.express.match.NodeTypeManagerTestImpl; +import com.ql.util.express.match.QLPattern; +import com.ql.util.express.match.QLPatternNode; + +public class QLPatternDefineTest { + INodeTypeManager manager = new NodeTypeManagerTestImpl(); + + @Test + public void testDefine() throws Exception { + String[] defines = new String[] { + //"ABC", + //"ABC^*", +// "\\(~$ID$\\)~#()", +// "CONST$(+^$(CONST|ID))^{1:222}#SQL", +// "(CONST|ID)$((*|/)^$CONST)^*", +// "(CONST|ID)$(,~$(CONST|ID))*#PARAMETER_LIST", +// "OPDATA$(.->FIELD_CALL^$ID->CONST_STRING)^*", +// "\\(->CHILD_EXPRESS", + "OP_LEVEL1|OP_LEVEL2|OP_LEVEL3|OP_LEVEL4|OP_LEVEL5|OP_LEVEL6|OP_LEVEL7|OP_LEVEL8|OP_LEVEL9|=|LEFT_BRACKET|RIGHT_BRACKET" + }; + for (String s : defines) { + QLPatternNode t = QLPattern.createPattern(manager,"ANONY_PATTERN", s); + System.out.println(t); + } + } +} diff --git a/src/test/java/com/ql/util/express/test/newmatch/SqlTest.java b/src/test/java/com/ql/util/express/test/newmatch/SqlTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ce80e32cdc0ff46e01890dfa75dab8638847d340 --- /dev/null +++ b/src/test/java/com/ql/util/express/test/newmatch/SqlTest.java @@ -0,0 +1,27 @@ +package com.ql.util.express.test.newmatch; + +import org.junit.Test; + +import com.ql.util.express.parse.ExpressNode; +import com.ql.util.express.parse.ExpressParse; +import com.ql.util.express.parse.KeyWordDefine4SQL; +import com.ql.util.express.parse.NodeTypeManager; + +public class SqlTest { + + public String[] testString ={ + "select id as id2 from upp_biz_order", + "select id as id2,name as name2 from upp_biz_order where a=1", + "select id as id2,name from upp_biz_order where 1=1", + }; + @Test + public void testDefine() throws Exception { + NodeTypeManager manager = new NodeTypeManager(new KeyWordDefine4SQL()); + ExpressParse parse = new ExpressParse(manager,null,false); + for(String text : testString){ + ExpressNode result = parse.parse(null, text, true, null); + System.out.print(result); + } + + } +} diff --git a/src/test/java/com/ql/util/express/test/newmatch/TestMatch.java b/src/test/java/com/ql/util/express/test/newmatch/TestMatch.java new file mode 100644 index 0000000000000000000000000000000000000000..d350fd14e52fdaf7e2e59abe8df5b5b710402144 --- /dev/null +++ b/src/test/java/com/ql/util/express/test/newmatch/TestMatch.java @@ -0,0 +1,118 @@ +package com.ql.util.express.test.newmatch; + +import java.util.ArrayList; +import java.util.List; + +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.IExpressContext; +import com.ql.util.express.test.ExpressContextExample; + +public class TestMatch { + @org.junit.Test + public void testExpress() throws Exception{ + ExpressRunner runner = new ExpressRunner(false,true); + String[][] expressTest = new String[][] { + {"1+2","3"}, + {"2-1","1"}, + {"2+(-1)","1"}, + {"(3+3)*(4+4)/3 + 8 - 2*2","20"}, + {"7==8","false"}, + {"!((8>=8) && !false) || 9==9","true"}, + {"a=(b=9)","9"}, + {"int a = 1+3","4"}, + {"(int[][] a = new int[2][2]).length","2"}, + {" f = (exportDef int b = (int a = 2+3))","5"}, + {"name=new String() + 100","100"}, + {"name=new String((3+3)*4+\"$\") + 100","24$100"}, + {"name=new String(\"xuannan-\") + 100","xuannan-100"}, + {"new String[2][10].length","2"}, + {"[1,2,3,4,5].length","5"}, + {"[1,2,3,4,5][2]","3"}, + {"[[1,2],[3,4]].length","2"}, + {"1000 + new String(\"abc\").substring(1).substring(1).length() + 100","1101"}, + {"new Object().getClass().getAnnotations().length","0"}, + {"new Object().getClass().getMethods()[1].getName()","wait"}, +// {"Object.class.getName().getClass().getMethods().length","72"}, + {"1/2","0"}, + {"1/(double)2","0.5"}, + {"(double)1/2","0.5"}, + {"((Object)\"ABC\").getClass().getName()","java.lang.String"}, + {"[[1,2],[3,4]][0][1]","2"}, + {"(new String[2])[1]","null"}, + {"max(2,100)","100"}, + {"max(max(1,2,3),min(2,100))","3"}, + {"true?1:2","1"}, + {"9==9?100+200:10+20","300"}, + {"9==8?100+200:20+20","40"}, + {"return a=100+90","190"}, + {"alias xuannan qianghui","null"}, + {"max 2-1,3,4+2","6"}, + {"int a = 2 + 1;b=100;return a + b","103"}, + {"{int a = 10;{int a = 20;} return a;}","10"}, + {"{int a = 10;{a = 20;} return a;}","20"}, + {"if true then return 100 else return 200","100"}, + {"if true then {return 100;} else {return 200;}","100"}, + {"if (false) then return 100 else return 200","200"}, + {"if (1!=1) then {return 100;} else {return 200;}","200"}, + {"if true then return 100","100"}, + {"if true then {return 100;} ","100"}, + {"if (false) then return 100","null"}, + {"if (1!=1) then {return 100;}","null"}, + {"if (true) return 100; else return 200","100"}, + {"if (true) {return 100;} else {return 200;}","100"}, + {"if (false) return 100; else return 200","200"}, + {"if (1!=1) {return 100;} else {return 200;}","200"}, + {"if (false) if(false) return 100;else return 200; else return 300;","300"}, + {"int a = 0;{a = a + 100;}{ a= a+ 200;}","300"}, + {"int a =0;for(int i=1;i<=10;i++){a = a + i;} return a;","55"}, + {"int a =0;for(int i=1;i<10;i++){if(i >5) break; a = a + 100;} return a;","500"}, + {"function abc(){return 100;} return abc()","100"}, + {"function abc(int a,int b){ return a + b;} return abc(1+100,2*100)","301"}, + {"macro abc { return a + 100;} int a = 100; return abc + 100","300"}, + {"class Person(String aName,int aYear){" + + "String name = aName;" + + "int year = aYear;" + + "function getName(){return name;}" + + "function getYear(){return year;}" + + "} " + + "Person person =new Person(\"xuannan\",100);" + + "return person.getName() + '-' + person.getYear();" + ,"xuannan-100"}, + {"map = NewMap('ABC':100,'BCD':200,'DEF':1000 + 1000);return map.get('BCD')","200"}, + {"Object[] abc = [];return abc.length","0"}, + {"2 in 2","true"}, + {"2 in (4,5,6)","false"}, + {"(-1)","-1"}, + {"/**1,2,3,4**/1+2","3"}, + {"1+/**1,2,3,4**/2+3","6"}, + {"(new String[3][5])[1].length","5"}, + {"class ABC(com.ql.util.express.test.BeanExample bean,String name){" + +"InnerClass a = new InnerClass();" + + "哈希值:{bean.hashCode();};" + + "class InnerClass(){" + + "int 计数 =200;" + + "};" + + "}" + + "return new ABC(new com.ql.util.express.test.BeanExample(),'xuannan').a.计数" , + "200" + }, + {";i=100;;","100"} + }; + for (int point = 0; point < expressTest.length; point++) { + String expressStr = expressTest[point][0]; + List errorList = new ArrayList(); + IExpressContext expressContext = new ExpressContextExample(null); + Object result = runner.execute(expressStr,expressContext, null, false,false); + if (expressTest[point][1].equalsIgnoreCase("null") + && result != null + || expressTest[point][1].equalsIgnoreCase(result==null?"null":result.toString()) == false) { + throw new Exception("处理错误,计算结果与预期的不匹配:" + expressStr + " = " + result + "但是期望值是:" + expressTest[point][1]); + } + System.out.println("Example " + point + " : " + expressStr + " = " + result); + System.out.println(expressContext); + if(errorList.size() > 0){ + System.out.println("\t\t系统输出的错误提示信息:" + errorList); + } + } + } +} diff --git a/src/test/java/com/ql/util/express/test/rating/RatingTest.java b/src/test/java/com/ql/util/express/test/rating/RatingTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a24d208580948d2d77a93d885d4f295c87a432fd --- /dev/null +++ b/src/test/java/com/ql/util/express/test/rating/RatingTest.java @@ -0,0 +1,52 @@ +package com.ql.util.express.test.rating; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; + +import com.ql.util.express.DefaultContext; +import com.ql.util.express.ExpressRunner; +/** + * 分成配置范例 + * @author xuannan + * + */ +public class RatingTest { + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Test + public void testRating( ) throws Exception { + Map logisticsOrder = new HashMap(); + Map tcOrder = new HashMap(); + Map goodsOrder = new HashMap(); + Map subjectValue = new HashMap(); + //设置物流订单信息 + logisticsOrder.put("重量",4); + logisticsOrder.put("仓储TP","玄难"); + logisticsOrder.put("物流TP","云殊"); + logisticsOrder.put("包装TP","千绝"); + //建立计算器 + ExpressRunner runner = new ExpressRunner(true,true); + //增加自定义函数 + runner.addFunction("费用科目",new SujectOperator("费用科目")); + //装载分成规则rating.ql文件 + runner.loadExpress("rating"); + //设置上下文 + DefaultContext context = new DefaultContext(); + context.put("物流订单", logisticsOrder); + context.put("交易订单", tcOrder); + context.put("仓储订单", goodsOrder); + context.put("费用科目", subjectValue); + //执行指令 + runner.executeByExpressName("rating",context, null, false,false,null); +// runner.executeByExpressName("rating",context, null, false,false,null); +// while(true){ +// runner.executeByExpressName("rating",context, null, false,false,null); +// } + //输出分成结果 + System.out.println("----------分成结果----------------"); + for(Object item : subjectValue.values()){ + System.out.println(item); + } + } +} diff --git a/src/test/java/com/ql/util/express/test/rating/RatingWithPropertyTest.java b/src/test/java/com/ql/util/express/test/rating/RatingWithPropertyTest.java new file mode 100644 index 0000000000000000000000000000000000000000..9a56718ecc154574e96f17477327861276afeaf9 --- /dev/null +++ b/src/test/java/com/ql/util/express/test/rating/RatingWithPropertyTest.java @@ -0,0 +1,48 @@ +package com.ql.util.express.test.rating; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; + +import com.ql.util.express.DefaultContext; +import com.ql.util.express.ExpressRunner; +/** + * 分成配置范例,通过动态属性来实现 + * @author xuannan + * + */ +public class RatingWithPropertyTest { + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Test + public void testRating( ) throws Exception { + Map logisticsOrder = new HashMap(); + Map tcOrder = new HashMap(); + Map goodsOrder = new HashMap(); + //设置物流订单信息 + logisticsOrder.put("重量",4); + logisticsOrder.put("仓储TPID","玄难"); + logisticsOrder.put("物流TPID","云殊"); + logisticsOrder.put("包装TPID","千绝"); + //建立计算器 + ExpressRunner runner = new ExpressRunner(); + //增加自定义函数 + runner.addFunction("费用科目",new SujectOperator("费用科目")); + //装载分成规则rating.ql文件 + runner.loadExpress("ratingWithProperty"); + //设置上下文 + DefaultContext context = new DefaultContext(); + context.put("物流订单", logisticsOrder); + context.put("交易订单", tcOrder); + context.put("仓储订单", goodsOrder); + SubjectMananger subjectMananger = new SubjectMananger(); + context.put("费用", subjectMananger); + + runner.executeByExpressName("ratingWithProperty", context, null, false,false,null); + //输出分成结果 + System.out.println("----------分成结果----------------"); + for(Object item : subjectMananger.getSubjectValues()){ + System.out.println(item); + } + } +} diff --git a/src/test/java/com/ql/util/express/test/rating/SubjectMananger.java b/src/test/java/com/ql/util/express/test/rating/SubjectMananger.java new file mode 100644 index 0000000000000000000000000000000000000000..a1be8652c553bdd12942d661e93278519afcf15c --- /dev/null +++ b/src/test/java/com/ql/util/express/test/rating/SubjectMananger.java @@ -0,0 +1,63 @@ +package com.ql.util.express.test.rating; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@SuppressWarnings({ "serial", "rawtypes" }) +public class SubjectMananger extends HashMap { + @SuppressWarnings("unchecked") + public Object get(Object userName){ + UserSubject userSubject = (UserSubject)super.get(userName); + if(userSubject == null){ + userSubject = new UserSubject(userName); + super.put(userName, userSubject); + } + return userSubject; + } + public Object put(String userName, Object userSubject){ + throw new RuntimeException("不运行的方法"); + } + public List getSubjectValues(){ + List result = new ArrayList(); + for(Object f : this.values()){ + UserSubject item = (UserSubject)f; + for(Object t : item.entrySet()){ + Map.Entry me = (Map.Entry)t; + SubjectValue value = new SubjectValue(); + value.userId = item.getUserId(); + value.subjectId = me.getKey(); + value.value = ((Number)me.getValue()).doubleValue(); + result.add(value); + } + } + return result; + } +} + +@SuppressWarnings({ "serial", "rawtypes" }) +class UserSubject extends HashMap { + Object userId; + public UserSubject(Object aUserId){ + super(); + this.userId = aUserId; + } + public Double get(String subjectId){ + Double value = (Double)super.get(subjectId); + if(value == null){ + return 0d; + } + return value; + } + @SuppressWarnings("unchecked") + public Object put(String subjectId, Object value){ + return super.put(subjectId, value); + } + public Object getUserId() { + return userId; + } +} + + + diff --git a/src/test/java/com/ql/util/express/test/rating/SubjectValue.java b/src/test/java/com/ql/util/express/test/rating/SubjectValue.java new file mode 100644 index 0000000000000000000000000000000000000000..a1a58959dcf36e5e04041b230c4a8e678794f178 --- /dev/null +++ b/src/test/java/com/ql/util/express/test/rating/SubjectValue.java @@ -0,0 +1,15 @@ +package com.ql.util.express.test.rating; + +/** + * 科目数据 + * @author xuannan + * + */ +public class SubjectValue { + public Object userId; + public Object subjectId; + public double value; + public String toString(){ + return "科目[" + userId + "," + subjectId +"] = " + value; + } +} diff --git a/src/test/java/com/ql/util/express/test/rating/SujectOperator.java b/src/test/java/com/ql/util/express/test/rating/SujectOperator.java new file mode 100644 index 0000000000000000000000000000000000000000..d2a525800622b6f697f4194424dfb4abd6ad25d1 --- /dev/null +++ b/src/test/java/com/ql/util/express/test/rating/SujectOperator.java @@ -0,0 +1,82 @@ +package com.ql.util.express.test.rating; + +import java.util.Map; + +import com.ql.util.express.ArraySwap; +import com.ql.util.express.InstructionSetContext; +import com.ql.util.express.OperateData; +import com.ql.util.express.Operator; +/** + * 科目操作符号 + * @author xuannan + * + */ +class SujectOperator extends Operator { + public SujectOperator(String aName) { + this.name = aName; + } + public SujectOperator(String aAliasName, String aName, String aErrorInfo) { + this.name = aName; + this.aliasName = aAliasName; + this.errorInfo = aErrorInfo; + } + + @SuppressWarnings("rawtypes") + public OperateData executeInner(InstructionSetContext context, + ArraySwap list) throws Exception { + if (list.length != 2) { + throw new Exception("科目操作的参数必须包括:科目主体ID和科目名称"); + } + Object userId = list.get(0).getObject(context) ; + Object subjectId = list.get(1).getObject(context); + if(userId == null || subjectId == null){ + throw new Exception("科目主体ID和科目名称不能为null"); + } + OperateData result = new OperateDataSubject((Map)context.get("费用科目"),userId,subjectId); + return result; + } + + @Override + public Object executeInner(Object[] list) throws Exception { + new Exception("不需要实现的方法").printStackTrace(); + throw new Exception("不需要实现的方法"); + } +} +@SuppressWarnings("rawtypes") +class OperateDataSubject extends OperateData{ + Object userId ; + Object subjectId ; + Map container; + + public OperateDataSubject(Map aContainer,Object aUserId,Object aSubjectId){ + super(null,Double.class); + this.userId = aUserId; + this.subjectId = aSubjectId; + this.container = aContainer; + } + public Class getDefineType(){ + return this.type; + } + public Object getObjectInner(InstructionSetContext context){ + String key = this.userId + "-" + this.subjectId; + SubjectValue subject = (SubjectValue) container.get(key); + if (subject == null) { + return 0d; + } else { + return subject.value; + } + } + @SuppressWarnings("unchecked") +public void setObject(InstructionSetContext parent, Object value) { + String key = this.userId +"-" + this.subjectId; + SubjectValue subject = (SubjectValue)container.get(key); + if(subject == null){ + subject = new SubjectValue(); + subject.subjectId = this.subjectId; + subject.userId = this.userId; + container.put(key,subject); + } + subject.value = ((Number)value).doubleValue(); + } + +} diff --git a/src/test/resources/Test.ql b/src/test/resources/Test.ql new file mode 100644 index 0000000000000000000000000000000000000000..505bab4c1776c83f65ef71d089dd87b3dd2aef42 --- /dev/null +++ b/src/test/resources/Test.ql @@ -0,0 +1,5 @@ + + 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); diff --git a/src/test/resources/TestFunctionParamerType.ql b/src/test/resources/TestFunctionParamerType.ql new file mode 100644 index 0000000000000000000000000000000000000000..5364db674a32e2b68eafbbc3743100aeb5a5240f --- /dev/null +++ b/src/test/resources/TestFunctionParamerType.ql @@ -0,0 +1,7 @@ +java.util.Map event = new java.util.HashMap(); + +java.util.Map auction = new java.util.HashMap(); +auction.put("title","title"); +auction.put("category","123456"); +event.put("auction",auction); +log.warn(auctionUtil.getText(event.auction.title,event.auction.category)); diff --git a/src/test/resources/example/approve.ql b/src/test/resources/example/approve.ql new file mode 100644 index 0000000000000000000000000000000000000000..3b21b013d12307e8f5618b7eaa287f738c73df56 --- /dev/null +++ b/src/test/resources/example/approve.ql @@ -0,0 +1,36 @@ +function 审批通过(String a,int b){ + System.out.println(a + "审批:金额:" + b); + return true; +} + +function 报销入账(int a){ + System.out.println("报销入卡:金额:"+a); +} + +function 打回修改(String a){ + System.out.println("重填:申请人:"+a); +} + + +如果 (审批通过(经理,金额)){ + 如果 (金额 大于 5000){ + 如果 (审批通过(总监,金额)){ + 如果 (审批通过(财务,金额)){ + 报销入账(金额) + }否则 { + 打回修改(申请人) + } + }否则 { + 打回修改(申请人) + } + }否则 { + 如果 (审批通过(财务,金额)){ + 报销入账(金额) + }否则 { + 打回修改(申请人) + } + } +}否则 { + 打回修改(申请人) +} +打印("完成") diff --git a/src/test/resources/example/approve1.ql b/src/test/resources/example/approve1.ql new file mode 100644 index 0000000000000000000000000000000000000000..9b34dcd9a6e6eaf87a3a23dfa54d679b09416c86 --- /dev/null +++ b/src/test/resources/example/approve1.ql @@ -0,0 +1,23 @@ + +如果 (审批通过(经理,金额)){ + 如果 (金额 大于 5000){ + 如果 (审批通过(总监,金额)){ + 如果 (审批通过(财务,金额)){ + 报销入账(金额) + }否则 { + 打回修改(申请人) + } + }否则 { + 打回修改(申请人) + } + }否则 { + 如果 (审批通过(财务,金额)){ + 报销入账(金额) + }否则 { + 打回修改(申请人) + } + } +}否则 { + 打回修改(申请人) +} +打印("完成") diff --git a/src/test/resources/example/approve2.ql b/src/test/resources/example/approve2.ql new file mode 100644 index 0000000000000000000000000000000000000000..ddd06e98b5f68bc990ad34f496e29feefe1f38f3 --- /dev/null +++ b/src/test/resources/example/approve2.ql @@ -0,0 +1,14 @@ +function 审批通过(String a,int b){ + System.out.println(a + "审批:金额:" + b); + if(b > 6000) + return false; + return true; +} + +function 报销入账(int a){ + System.out.println("报销入卡:金额:"+a); +} + +function 打回修改(String a){ + System.out.println("重填:申请人:"+a); +} diff --git a/src/test/resources/functiondef.ql b/src/test/resources/functiondef.ql new file mode 100644 index 0000000000000000000000000000000000000000..2c0aea2b12b9237c188099bed7da6732004022c8 --- /dev/null +++ b/src/test/resources/functiondef.ql @@ -0,0 +1,16 @@ +function add(int a,int b){ + return a+b; +}; + +function sub(int a,int b){ + return a - b; +}; + +macro 累加 {qh = qh + 100;}; + +macro initial { + exportDef int qh; + exportAlias a qh; + a = 0; +}; + diff --git a/src/test/resources/includeFunction.ql b/src/test/resources/includeFunction.ql new file mode 100644 index 0000000000000000000000000000000000000000..4cb8e9e161fda9adb12484363c0a68b2572350af --- /dev/null +++ b/src/test/resources/includeFunction.ql @@ -0,0 +1,8 @@ +function add(int a,int b){ + return a+b; +}; + +function sub(int a,int b){ + return a - b; +}; + diff --git a/src/test/resources/includeMacro.ql b/src/test/resources/includeMacro.ql new file mode 100644 index 0000000000000000000000000000000000000000..3019239399dfb71cbf1e4a394c9536dddbe3f195 --- /dev/null +++ b/src/test/resources/includeMacro.ql @@ -0,0 +1,8 @@ +macro 累加 {qh = qh + 100;}; + +macro initial { + exportDef int qh; + exportAlias a qh; + a = 0; +}; + diff --git a/src/test/resources/includeRoot.ql b/src/test/resources/includeRoot.ql new file mode 100644 index 0000000000000000000000000000000000000000..a123c484fff611d67ef76f358daac320a9542450 --- /dev/null +++ b/src/test/resources/includeRoot.ql @@ -0,0 +1,18 @@ + +if(true)then {1==1} else{ 3==3} ; + +include includeFunction; + +exportDef int mm =1000; + +include includeMacro; + +initial; +累加; +累加; +累加; + +mm = mm + 1; +a = a + 1000000; +System.out.println(a); +return add(a,4) + sub(a,9); diff --git a/src/test/resources/log4j.properties b/src/test/resources/log4j.properties new file mode 100644 index 0000000000000000000000000000000000000000..9dcc9679d9aea0f3f9618593656f858dd7ae5287 --- /dev/null +++ b/src/test/resources/log4j.properties @@ -0,0 +1,17 @@ + +log4j.appender.file=org.apache.log4j.DailyRollingFileAppender +log4j.appender.file.File=Test_LOG4j.log +log4j.appender.file.layout=org.apache.log4j.PatternLayout +log4j.appender.file.layout.ConversionPattern=[%d] [%t] (%F:%L) %-5p %c - %m%n + +log4j.appender.console=org.apache.log4j.ConsoleAppender +log4j.appender.console.layout=org.apache.log4j.PatternLayout +log4j.appender.console.layout.ConversionPattern=[%d] [%t] (%F:%L) %-5p %c - %m%n + +log4j.appender.html=org.apache.log4j.DailyRollingFileAppender +log4j.appender.html.File=Test_LOG4j.log +log4j.appender.html.layout=org.apache.log4j.HTMLLayout + +log4j.rootLogger=error,console +log4j.logger.com.ql = debug +log4j.logger.org.springframework = error diff --git a/src/test/resources/main.ql b/src/test/resources/main.ql new file mode 100644 index 0000000000000000000000000000000000000000..471eff469cfbaeb25bacb59bfe351f08fd83d41b --- /dev/null +++ b/src/test/resources/main.ql @@ -0,0 +1,11 @@ +initial; +累加; +累加; +累加; + +if(true)then {1==1} else{ 3==3} ; +exportDef int mm =1000; +mm = mm + 1; +a = a + 1000000; +System.out.println(a); +return add(a,4) + sub(a,9); diff --git a/src/test/resources/rating.ql b/src/test/resources/rating.ql new file mode 100644 index 0000000000000000000000000000000000000000..75b26bbf7fb0c7a9037e20cd5a2963899b897162 --- /dev/null +++ b/src/test/resources/rating.ql @@ -0,0 +1,8 @@ +费用科目(物流订单.仓储TP,"仓储费")= 物流订单.重量 * 0.5 ; + +if(物流订单.重量 > 5) then{ + 费用科目(物流订单.物流TP,"运输费")= 3.0 + (物流订单.重量 - 5 ) * 1.5 ; +} else { + 费用科目(物流订单.物流TP,"运输费")= 3.0; +}; +费用科目(物流订单.包装TP,"包装费")= 物流订单.重量 * 2.5 ; diff --git a/src/test/resources/ratingWithProperty.ql b/src/test/resources/ratingWithProperty.ql new file mode 100644 index 0000000000000000000000000000000000000000..3f44d6fbfb15b00752d9ebcd9f4ca248d63abfb4 --- /dev/null +++ b/src/test/resources/ratingWithProperty.ql @@ -0,0 +1,7 @@ +alias 仓储TP 物流订单.仓储TPID; +alias 物流TP 物流订单.物流TPID; +alias 包装TP 物流订单.包装TPID; +仓储费 = 100; +费用.仓储TP.仓储费 = 物流订单.重量 * 0.5 ; +费用.物流TP.运输费= 3.0; +费用.包装TP.包装费= 物流订单.重量 * 2.5 ; diff --git a/src/test/resources/spring-express-config.xml b/src/test/resources/spring-express-config.xml new file mode 100644 index 0000000000000000000000000000000000000000..cabb2b8b490f419a269f3626da0e44ff6ca84d4e --- /dev/null +++ b/src/test/resources/spring-express-config.xml @@ -0,0 +1,6 @@ + + + + + +