fel兼容多值计算
fel 可以实现常见的单值计算,但是除了自定义函数特殊写以外都是单值计算。
有些时候我们需要支持多值计算。比如两个数组A+ 数据B=数组C(C 的结果是 A 和B 对应下标的值分别相加)
方法1,我们可以子定义add 函数,(下面的例子没有考虑类型异常,只能参考不能真实使用),这样我们就要能使用 add(集合A,集合B) 了。
class Add extends CommonFunction{ @Override public String getName() { return "add"; } @Override public Object call(FelNode node, FelContext context) { return super.call(node, context); } @Override public SourceBuilder toMethod(FelNode node, FelContext ctx) { return super.toMethod(node, ctx); } @Override public Object call(Object[] arguments) { Object args0 = arguments[0]; Object args1 = arguments[1]; if( args0 instanceof List || args1 instanceof List ) { if( args0 instanceof List && !(args1 instanceof List) ) { List list0 = (List)args0; return (Integer)(list0.get(0)) + (Integer)args1; } if( !(args0 instanceof List) && (args1 instanceof List) ) { List list1 = (List)args1; return (Integer)(list1.get(0)) + (Integer)args0; } List<Integer> rt = new ArrayList<>(); List list0 = (List)args0; List list1 = (List)args1; for( int i = 0;i<list0.size()&&i<list1.size();i++ ) { rt.add( (Integer)list0.get(i) + (Integer)list1.get(i) ); } return rt; }else { return (Integer)args0 + (Integer)args1; } } }
方法2,我们覆盖 原来对于+符号的定义。这样我们就能使用 集合A+集合B了
package com.greenpineyu.fel.function.operator; import static com.greenpineyu.fel.common.NumberUtil.toDouble; import java.math.BigDecimal; import java.math.BigInteger; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.List; import com.greenpineyu.fel.Expression; import com.greenpineyu.fel.common.NumberUtil; import com.greenpineyu.fel.common.ObjectUtils; import com.greenpineyu.fel.common.ReflectUtil; import com.greenpineyu.fel.compile.FelMethod; import com.greenpineyu.fel.compile.SourceBuilder; import com.greenpineyu.fel.context.FelContext; import com.greenpineyu.fel.function.StableFunction; import com.greenpineyu.fel.parser.FelNode; public class Add extends StableFunction { public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); /* * (non-Javadoc) * * @see .script.function.Function#call(.script.AstNode, * .script.context.ScriptContext) */ public Object call(FelNode node, FelContext context) { Object[] children = evalArgs(node, context); return call(children); } public static Object[] evalArgs(FelNode node, FelContext context) { Object[] returnMe = null; List<FelNode> children = node.getChildren(); if(children!=null&& children.size()>0){ Object[] args = children.toArray(); int size = args.length; returnMe = new Object[size]; System.arraycopy(args, 0, returnMe, 0, size); for (int i = 0; i < size; i++) { Object child = args[i]; if (child instanceof Expression) { Expression childExp = ((Expression) child); returnMe[i] = childExp.eval(context); } } } return returnMe; } public Object call(Object[] arguments) { Object args0 = arguments[0]; Object args1 = arguments[1]; if( args0 instanceof List || args1 instanceof List ) { if( args0 instanceof List && !(args1 instanceof List) ) { List list0 = (List)args0; return (Integer)(list0.get(0)) + (Integer)args1; } if( !(args0 instanceof List) && (args1 instanceof List) ) { List list1 = (List)args1; return (Integer)(list1.get(0)) + (Integer)args0; } List<Integer> rt = new ArrayList<>(); List list0 = (List)args0; List list1 = (List)args1; for( int i = 0;i<list0.size()&&i<list1.size();i++ ) { rt.add( (Integer)list0.get(i) + (Integer)list1.get(i) ); } return rt; }else { return (Integer)args0 + (Integer)args1; } } public String getName() { return "+"; } public FelMethod toMethod(FelNode node, FelContext ctx) { Class<?> type = null; List<FelNode> children = node.getChildren(); StringBuilder sb = new StringBuilder(); if (children.size() == 2) { FelNode left = children.get(0); SourceBuilder lm = left.toMethod(ctx); appendArg(sb, lm,ctx,left); Class<?> leftType = lm.returnType(ctx, left); FelNode right = children.get(1); sb.append("+"); SourceBuilder rm = right.toMethod(ctx); Class<?> rightType = rm.returnType(ctx, right); if(CharSequence.class.isAssignableFrom(leftType)){ type = leftType; } else if (CharSequence.class.isAssignableFrom(rightType)) { type = rightType; }else if(ReflectUtil.isPrimitiveOrWrapNumber(leftType) &&ReflectUtil.isPrimitiveOrWrapNumber(rightType)){ type = NumberUtil.arithmeticClass(leftType, rightType); }else { //涓嶆敮鎸佺殑绫诲瀷锛岃繑鍥炲瓧绗︿覆銆� type = String.class; } appendArg(sb, rm,ctx,right); } else if (children.size() == 1) { FelNode right = children.get(0); SourceBuilder rm = right.toMethod(ctx); Class<?> rightType = rm.returnType(ctx, right); if(ReflectUtil.isPrimitiveOrWrapNumber(rightType)){ appendArg(sb, rm,ctx,right); } type = rightType; } // appendArg(sb, rm,ctx,right); FelMethod m = new FelMethod(type, sb.toString()); return m; } private void appendArg(StringBuilder sb, SourceBuilder argMethod,FelContext ctx,FelNode node) { Class<?> t = argMethod.returnType(ctx, node); sb.append("("); if (ReflectUtil.isPrimitiveOrWrapNumber(t) || CharSequence.class.isAssignableFrom(t)) { // 鏁板�煎瀷鍜屽瓧绗﹀瀷鏃讹紝鐩存帴娣诲姞 sb.append(argMethod.source(ctx, node)); } else { sb.append("ObjectUtils.toString(").append(argMethod.source(ctx, node)) .append(")"); } sb.append(")"); } }
测试一下:
@Test public void test15() { FelEngine felEngine = new FelEngineImpl(); felEngine.addFun( new Add() ); FelContext context = felEngine.getContext(); context.set("a", Arrays.asList(3,6,9)); context.set("b", Arrays.asList(2,1,3)); context.set("c", Arrays.asList(2,2,2)); Object evalRt = felEngine.eval("add(add(a,b),c)"); System.out.println( JSONObject.toJSON( evalRt ) ); Object evalRt2 = felEngine.eval("(a+b)+c"); System.out.println( JSONObject.toJSON( evalRt2 ) ); Object evalRt3 = felEngine.eval("add((a+b),c)"); System.out.println( JSONObject.toJSON( evalRt3 ) ); }
允许结果: 改动后传入单值,返回单值,传入多值,返回集合,如果考虑统一,可以都返回集合,并且要求入参都是集合。
同理,有需要可以吧所有运算符都重写一遍,代码嫉妒类似。工作量不高。也就17 个而已。
另外解决问题的办法不止这两种。
如果没有特殊的历史原因,一般用方式2 应该是最简单的。影响最小的。 这种方式改动小,只是利用Java类加载顺序覆盖了以前的运算符逻辑。
能耍的时候就一定要耍,不能耍的时候一定要学。
天道酬勤,贵在坚持
posted on 2022-04-06 18:02 zhangyukun 阅读(243) 评论(0) 编辑 收藏 举报