Răsfoiți Sursa

支持嵌套lambda,新增lambda错误提示

kangjie 5 ani în urmă
părinte
comite
1ec7a2ce1c

+ 9 - 2
src/main/java/org/ssssssss/magicapi/expression/interpreter/JavaReflection.java

@@ -1,12 +1,15 @@
 
 package org.ssssssss.magicapi.expression.interpreter;
 
+import org.ssssssss.magicapi.expression.parsing.ArrayLikeLambdaExecutor.LambdaExecuteException;
+
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 
+
 public class JavaReflection extends AbstractReflection {
 	private final Map<Class<?>, Map<String, Field>> fieldCache = new ConcurrentHashMap<Class<?>, Map<String, Field>>();
 	private final Map<Class<?>, Map<MethodSignature, Method>> methodCache = new ConcurrentHashMap<Class<?>, Map<MethodSignature, Method>>();
@@ -376,8 +379,12 @@ public class JavaReflection extends AbstractReflection {
 		try {
 			return javaMethod.invoke(obj, arguments);
 		} catch (Throwable t) {
-			throw new RuntimeException("Couldn't call method '" + javaMethod.getName() + "' with arguments '" + Arrays.toString(arguments)
-				+ "' on object of type '" + obj.getClass().getSimpleName() + "'.", t);
+			if (t.getCause() instanceof LambdaExecuteException) {
+				throw new RuntimeException(t.getCause().getMessage(), t);
+			} else {
+				throw new RuntimeException("Couldn't call method '" + javaMethod.getName() + "' with arguments '" + Arrays.toString(arguments)
+						+ "' on object of type '" + obj.getClass().getSimpleName() + "'.", t);
+			}
 		}
 	}
 

+ 36 - 5
src/main/java/org/ssssssss/magicapi/expression/parsing/ArrayLikeLambdaExecutor.java

@@ -36,7 +36,7 @@ public class ArrayLikeLambdaExecutor {
             initialMap.put(name, ArrayLikeLambdaExecutor.class.getMethod(name, Object.class, Object[].class));
         } catch (NoSuchMethodException e) {
             e.printStackTrace();
-            throw new RuntimeException(e);
+            throw new LambdaExecuteException(e);
         }
     }
 
@@ -69,7 +69,7 @@ public class ArrayLikeLambdaExecutor {
             Enumeration<Object> en = (Enumeration<Object>) arrayLike;
             return Collections.list(en);
         }
-        throw new RuntimeException("未实现");
+        throw new LambdaExecuteException("未实现");
     }
 
     @SuppressWarnings("unchecked")
@@ -145,7 +145,7 @@ public class ArrayLikeLambdaExecutor {
             }
             Object result = handler.apply(args.toArray());
             if (!(result instanceof Boolean)) {
-                throw new RuntimeException("lambda函数 filter 的结果非布尔类型");
+                throw new LambdaExecuteException("lambda函数 filter 的结果非布尔类型");
             }
             if ((Boolean) result) {
                 results.add(obj);
@@ -192,7 +192,7 @@ public class ArrayLikeLambdaExecutor {
             }
             Object result = handler.apply(args.toArray());
             if (!(result instanceof Boolean)) {
-                throw new RuntimeException("lambda函数 every 的结果非布尔类型");
+                throw new LambdaExecuteException("lambda函数 every 的结果非布尔类型");
             }
             if ( !(Boolean)result ) {
                 return Boolean.FALSE;
@@ -216,7 +216,7 @@ public class ArrayLikeLambdaExecutor {
             }
             Object result = handler.apply(args.toArray());
             if (!(result instanceof Boolean)) {
-                throw new RuntimeException("lambda函数some的结果非布尔类型");
+                throw new LambdaExecuteException("lambda函数some的结果非布尔类型");
             }
             if ( (Boolean)result ) {
                 return Boolean.TRUE;
@@ -254,4 +254,35 @@ public class ArrayLikeLambdaExecutor {
         }
     }
 
+    public static class LambdaExecuteException extends RuntimeException{
+        private int argumentIndex;
+
+        public int getArgumentIndex() {
+            return argumentIndex;
+        }
+
+        public void setArgumentIndex(int argumentIndex) {
+            this.argumentIndex = argumentIndex;
+        }
+
+        public LambdaExecuteException() {
+            super();
+        }
+
+        public LambdaExecuteException(String message) {
+            super(message);
+        }
+
+        public LambdaExecuteException(String message, Throwable cause) {
+            super(message, cause);
+        }
+
+        public LambdaExecuteException(Throwable cause) {
+            super(cause);
+        }
+
+        protected LambdaExecuteException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+            super(message, cause, enableSuppression, writableStackTrace);
+        }
+    }
 }

+ 7 - 1
src/main/java/org/ssssssss/magicapi/expression/parsing/Ast.java

@@ -10,13 +10,13 @@ import org.ssssssss.magicapi.expression.ExpressionTemplateContext;
 import org.ssssssss.magicapi.expression.interpreter.AbstractReflection;
 import org.ssssssss.magicapi.expression.interpreter.AstInterpreter;
 import org.ssssssss.magicapi.expression.interpreter.JavaReflection;
+import org.ssssssss.magicapi.expression.parsing.ArrayLikeLambdaExecutor.LambdaExecuteException;
 
 import javax.xml.transform.Source;
 import java.io.IOException;
 import java.lang.reflect.Array;
 import java.lang.reflect.InvocationTargetException;
 import java.util.*;
-import java.util.concurrent.atomic.AtomicInteger;
 
 
 /** Templates are parsed into an abstract syntax tree (AST) nodes by a Parser. This class contains all AST node types. */
@@ -1271,6 +1271,12 @@ public abstract class Ast {
                     } catch (Throwable t) {
                         t.printStackTrace();
                         // fall through
+                        if (t.getCause()!=null && t.getCause().getCause() instanceof LambdaExecuteException) {
+                            LambdaExecuteException lee = (LambdaExecuteException)t.getCause().getCause();
+                            List<Expression> args = getArguments();
+                            LambdaAccess lambdaAccess = (LambdaAccess)args.get(lee.getArgumentIndex());
+                            ExpressionError.error(t.getMessage(), lambdaAccess.getFunction().getSpan());
+                        }
                     }
                 }
 

+ 11 - 8
src/main/java/org/ssssssss/magicapi/expression/parsing/Parser.java

@@ -254,13 +254,13 @@ public class Parser {
 	private static List<Expression> parseArgumentsNotExpect (TokenStream stream) {
 		List<Expression> arguments = new ArrayList<Expression>();
 		while (stream.hasMore() && !stream.match(TokenType.RightParantheses, false)) {
-			boolean f1 = false, f2 = false;
+			boolean lambdaMultArgs = false, foundLambda = false;
 			int c = 0;
 			while (stream.hasNext()) {
 				c++;
 				stream.next();
-				if (f1 && stream.match(TokenType.Lambda, false)) {
-					f2 = true;
+				if (lambdaMultArgs && stream.match(TokenType.Lambda, false)) {
+					foundLambda = true;
 					int count = c;
 					for (int i = 0; i < count - 1; i++) {
 						stream.prev();
@@ -269,12 +269,15 @@ public class Parser {
 					break;
 				}
 				if (stream.match(TokenType.RightParantheses, false)) {
-					f1 = true;
+					lambdaMultArgs = true;
 				} else {
-					f1 = false;
+					lambdaMultArgs = false;
+					if (!stream.match(false, TokenType.Identifier, TokenType.Comma)) {
+						break;
+					}
 				}
 			}
-			if (!f2) {
+			if (!foundLambda) {
 				int count = c;
 				for (int i = 0; i < count; i++) {
 					stream.prev();
@@ -282,7 +285,7 @@ public class Parser {
 				}
 			}
 			arguments.add(parseExpression(stream));
-			if (f1 && f2) {
+			if (lambdaMultArgs && foundLambda) {
 				while (stream.match(TokenType.Comma, true)) {
 					arguments.add(parseExpression(stream));
 				}
@@ -292,7 +295,7 @@ public class Parser {
 //				if (stream.match(TokenType.Lambda, false)) {
 //					return arguments;
 //				} else {
-					stream.expect(TokenType.Comma);
+				stream.expect(TokenType.Comma);
 //				}
 			}
 		}

+ 5 - 0
src/main/java/org/ssssssss/magicapi/expression/parsing/Tokenizer.java

@@ -219,4 +219,9 @@ public class Tokenizer {
         }
 		return tokens;
 	}
+
+	public static void main(String[] args) {
+		new Tokenizer().tokenize("1212134dscxd${resp.abc().xxx}").forEach(System.out::println);
+
+	}
 }