Browse Source

lambda函数 reduce和sort支持

kangjie 5 years ago
parent
commit
2f7ccac49d

+ 1 - 1
src/main/java/org/ssssssss/expression/ExpressionEngine.java

@@ -23,7 +23,7 @@ public class ExpressionEngine {
 		list.add("yyy");
 		list.add("");
 		params.put("list", list);
-		Object result = engine.execute("${list.filter(e->list.filter(e->!e.isEmpty()).size() > 1)}", params);
+		Object result = engine.execute("${list.sort((a,b)->a.compareTo(b))}", params);
 		System.out.println(result);
 
 	}

+ 95 - 4
src/main/java/org/ssssssss/expression/parsing/ArrayLikeLambdaExecutor.java

@@ -1,8 +1,11 @@
 package org.ssssssss.expression.parsing;
 
+import java.lang.reflect.Array;
 import java.lang.reflect.Method;
 import java.util.*;
+import java.util.function.Function;
 import java.util.function.Supplier;
+import java.util.stream.IntStream;
 
 public class ArrayLikeLambdaExecutor {
 
@@ -15,7 +18,8 @@ public class ArrayLikeLambdaExecutor {
         Set<String> set = new HashSet<>();
         addSupport(temp, set, "map");
         addSupport(temp, set, "filter");
-//        addSupport(temp, set, "reduce");
+        addSupport(temp, set, "reduce");
+        addSupport(temp, set, "sort");
         SUPPORT_METHOD = Collections.unmodifiableSet(set);
         METHODS = Collections.unmodifiableMap(temp);
     }
@@ -43,6 +47,14 @@ public class ArrayLikeLambdaExecutor {
             SourceAndParsed<Object, Object> result = (SourceAndParsed<Object, Object>) ((Supplier) args.get(j)).get();
             spConsumer.accept(results, result);
         }
+        Object result = toOriginType(arrayLike, results);
+        if (result != null) {
+            return result;
+        }
+        throw new RuntimeException("未实现");
+    }
+
+    private static Object toOriginType(Object arrayLike, List<Object> results) {
         if (arrayLike instanceof Collection) {
             return results;
         } else if (arrayLike.getClass().isArray()) {
@@ -52,15 +64,64 @@ public class ArrayLikeLambdaExecutor {
         } else if (arrayLike instanceof Enumeration) {
             return results;
         }
+        return null;
+    }
+
+    private static List<Object> arrayLikeToList(Object arrayLike) {
+        if (arrayLike instanceof Collection) {
+            return new ArrayList<>((Collection<?>) arrayLike);
+        } else if (arrayLike.getClass().isArray()) {
+            List<Object> list = new ArrayList<>(Array.getLength(arrayLike));
+            IntStream.range(0, Array.getLength(arrayLike)).forEach(i->list.add(Array.get(arrayLike, i)));
+            return list;
+        } else if (arrayLike instanceof Iterator) {
+            List<Object> list = new ArrayList<>();
+            Iterator<Object> it = (Iterator<Object>) arrayLike;
+            it.forEachRemaining(list::add);
+            return list;
+        } else if (arrayLike instanceof Enumeration) {
+            Enumeration<Object> en = (Enumeration<Object>) arrayLike;
+            return Collections.list(en);
+        }
         throw new RuntimeException("未实现");
     }
 
+    @SuppressWarnings("unchecked")
+    public static Object sort(Object arrayLike, Object... arguments) {
+        List<Object> results = null;
+        MultipleArgumentsLambda mal = (MultipleArgumentsLambda) arguments[0];
+        Function<Object[], Object> handler = mal.getHandler();
+        List<Object> coll = arrayLikeToList(arrayLike);
+        if (coll.isEmpty() || coll.size() == 1) {
+            return toOriginType(arrayLike, coll);
+        }
+        coll.sort((o1, o2) -> {
+            Object val = handler.apply(new Object[]{o1, o2});
+            if (!(val instanceof Integer)) {
+                throw new IllegalStateException("lambda 函数 sort 必须返回int类型结果");
+            }
+            return (Integer) val;
+        });
+        return toOriginType(arrayLike, coll);
+    }
+
 
     @SuppressWarnings("unchecked")
     public static Object reduce(Object arrayLike, Object... arguments) {
-        eachParse(arrayLike, arguments[0], (list, sp) -> list.add(sp.getParsed()));
-        System.out.println();
-        return null;
+        MultipleArgumentsLambda mal = (MultipleArgumentsLambda) arguments[0];
+        Function<Object[], Object> handler = mal.getHandler();
+        List<?> coll = arrayLikeToList(arrayLike);
+        if (coll.isEmpty()) {
+            return null;
+        }
+        if (coll.size() == 1) {
+            return coll.get(0);
+        }
+        Object result = coll.get(0);
+        for (int i = 1; i < coll.size(); i++) {
+            result = handler.apply(new Object[]{result, coll.get(i)});
+        }
+        return result;
     }
 
     @SuppressWarnings("unchecked")
@@ -81,6 +142,36 @@ public class ArrayLikeLambdaExecutor {
         });
     }
 
+
+    public static class MultipleArgumentsLambda {
+        private List<Ast.Expression> args;
+        private Function<Object[], Object> handler;
+
+        public MultipleArgumentsLambda(Function<Object[], Object> handler) {
+            this.handler = handler;
+        }
+        public MultipleArgumentsLambda(List<Ast.Expression> args, Function<Object[], Object> handler) {
+            this.args = args;
+            this.handler = handler;
+        }
+
+        public List<Ast.Expression> getArgs() {
+            return args;
+        }
+
+        public void setArgs(List<Ast.Expression> args) {
+            this.args = args;
+        }
+
+        public Function<Object[], Object> getHandler() {
+            return handler;
+        }
+
+        public void setHandler(Function<Object[], Object> handler) {
+            this.handler = handler;
+        }
+    }
+
     public interface SPConsumer {
         void accept(List<Object> list, SourceAndParsed<Object, Object> sp);
     }

+ 21 - 2
src/main/java/org/ssssssss/expression/parsing/Ast.java

@@ -1050,7 +1050,25 @@ public abstract class Ast {
                 if (arrLikeObj instanceof Collection) {
                     Collection<?> coll = (Collection<?>) arrLikeObj;
                     if (elements.size() > 1) {
-                        return this;
+                        AtomicInteger ai = new AtomicInteger();
+                        return new ArrayLikeLambdaExecutor.MultipleArgumentsLambda(elements, new Function<Object[], Object>() {
+                            @Override
+                            public Object apply(Object[] arguments) {
+                                try {
+                                    context.push();
+                                    for (int i = 0; i < elements.size() && i < arguments.length; i++) {
+                                        Expression expression = elements.get(i);
+                                        context.setOnCurrentScope(expression.getSpan().getText(), arguments[i]);
+                                    }
+                                    return function.evaluate(template, context);
+                                } catch (IOException e) {
+                                    e.printStackTrace();
+                                    throw new RuntimeException(e);
+                                } finally {
+                                    context.pop();
+                                }
+                            }
+                        });
                     }
                     AtomicInteger ai = new AtomicInteger();
                     return coll.stream().map(o -> ((Supplier) () -> {
@@ -1062,11 +1080,12 @@ public abstract class Ast {
                             }
                             context.setOnCurrentScope("_i", ai.getAndIncrement());
                             Object res = function.evaluate(template, context);
-                            context.pop();
                             return new ArrayLikeLambdaExecutor.SourceAndParsed<>(o, res);
                         } catch (IOException e) {
                             e.printStackTrace();
                             throw new RuntimeException(e);
+                        } finally {
+                            context.pop();
                         }
                     })).collect(Collectors.toList());
                 }