参数返回值
9 | * @param 参数类型
10 | */
11 | public interface Callable {
12 |
13 | R call(P... arg);
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/greenpineyu/fel/common/FelBuilder.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.common;
2 |
3 | import java.io.File;
4 | import java.util.HashSet;
5 | import java.util.Set;
6 |
7 | import com.greenpineyu.fel.security.RegexSecurityMgr;
8 | import com.greenpineyu.fel.security.SecurityMgr;
9 |
10 | public class FelBuilder {
11 |
12 | /**
13 | * 构建安全管理器
14 | * @return
15 | */
16 | public static SecurityMgr newSecurityMgr() {
17 | Set disables = new HashSet();
18 | disables.add(System.class.getCanonicalName() + ".*");
19 | disables.add(Runtime.class.getCanonicalName() + ".*");
20 | disables.add(Process.class.getCanonicalName() + ".*");
21 | disables.add(File.class.getCanonicalName() + ".*");
22 | disables.add("java.net.*");
23 | disables.add("com.greenpineyu.fel.compile.*");
24 | disables.add("com.greenpineyu.fel.security.*");
25 | return new RegexSecurityMgr(null, disables);
26 | }
27 |
28 | public static void main(String[] args) {
29 | System.out.println(System.class.getCanonicalName());
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/greenpineyu/fel/common/Null.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.common;
2 |
3 | /**
4 | * 用于表示Null值
5 | * @author yuqingsong
6 | *
7 | */
8 | public class Null {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/com/greenpineyu/fel/common/ObjectUtils.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.common;
2 |
3 |
4 | public class ObjectUtils {
5 | /**
6 | * Compares two objects for equality, where either one or both
7 | * objects may be {@code null}.
8 | *
9 | *
10 | * ObjectUtils.equals(null, null) = true
11 | * ObjectUtils.equals(null, "") = false
12 | * ObjectUtils.equals("", null) = false
13 | * ObjectUtils.equals("", "") = true
14 | * ObjectUtils.equals(Boolean.TRUE, null) = false
15 | * ObjectUtils.equals(Boolean.TRUE, "true") = false
16 | * ObjectUtils.equals(Boolean.TRUE, Boolean.TRUE) = true
17 | * ObjectUtils.equals(Boolean.TRUE, Boolean.FALSE) = false
18 | *
19 | *
20 | * @param object1 the first object, may be {@code null}
21 | * @param object2 the second object, may be {@code null}
22 | * @return {@code true} if the values of both objects are the same
23 | */
24 | public static boolean equals(Object object1, Object object2) {
25 | if (object1 == object2) {
26 | return true;
27 | }
28 | if ((object1 == null) || (object2 == null)) {
29 | return false;
30 | }
31 | return object1.equals(object2);
32 | }
33 |
34 | /**
35 | * Gets the {@code toString} of an {@code Object} returning
36 | * an empty string ("") if {@code null} input.
37 | *
38 | *
39 | * ObjectUtils.toString(null) = ""
40 | * ObjectUtils.toString("") = ""
41 | * ObjectUtils.toString("bat") = "bat"
42 | * ObjectUtils.toString(Boolean.TRUE) = "true"
43 | *
44 | *
45 | * @see StringUtils#defaultString(String)
46 | * @see String#valueOf(Object)
47 | * @param obj the Object to {@code toString}, may be null
48 | * @return the passed in Object's toString, or nullStr if {@code null} input
49 | * @since 2.0
50 | */
51 | public static String toString(Object obj) {
52 | return obj == null ? "" : obj.toString();
53 | }
54 |
55 | /**
56 | * Compares two objects for inequality, where either one or both
57 | * objects may be {@code null}.
58 | *
59 | *
60 | * ObjectUtils.notEqual(null, null) = false
61 | * ObjectUtils.notEqual(null, "") = true
62 | * ObjectUtils.notEqual("", null) = true
63 | * ObjectUtils.notEqual("", "") = false
64 | * ObjectUtils.notEqual(Boolean.TRUE, null) = true
65 | * ObjectUtils.notEqual(Boolean.TRUE, "true") = true
66 | * ObjectUtils.notEqual(Boolean.TRUE, Boolean.TRUE) = false
67 | * ObjectUtils.notEqual(Boolean.TRUE, Boolean.FALSE) = true
68 | *
69 | *
70 | * @param object1 the first object, may be {@code null}
71 | * @param object2 the second object, may be {@code null}
72 | * @return {@code false} if the values of both objects are the same
73 | */
74 | public static boolean notEqual(Object object1, Object object2) {
75 | return ObjectUtils.equals(object1, object2) == false;
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/main/java/com/greenpineyu/fel/common/ReflectUtil.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.common;
2 |
3 | import java.lang.reflect.Method;
4 | import java.util.HashMap;
5 | import java.util.Map;
6 |
7 | public class ReflectUtil {
8 |
9 | /**
10 | * key为基本类型及其包装类型,value为包装类型
11 | */
12 | static final Map,Class>> wrapperCls;
13 | /**
14 | * key为基本类型及其包装类型,value为基本类型
15 | */
16 | static final Map,Class>> primitiveCls;
17 |
18 | static final Map,Class>> numberClassMap;
19 | static{
20 | numberClassMap = wrapperNumberCls();
21 | primitiveCls = new HashMap, Class>>(primitiveNumberCls());
22 | primitiveCls.put(boolean.class, boolean.class);
23 | primitiveCls.put(Boolean.class, boolean.class);
24 |
25 | wrapperCls = new HashMap, Class>>(wrapperNumberCls());
26 | wrapperCls.put(boolean.class, Boolean.class);
27 | wrapperCls.put(Boolean.class, Boolean.class);
28 | }
29 |
30 | private static Map,Class>> primitiveNumberCls() {
31 | Map,Class>> map = new HashMap, Class>>();
32 | map.put(byte.class, byte.class);
33 | map.put(Byte.class, byte.class);
34 |
35 | map.put(short.class, short.class);
36 | map.put(Short.class, short.class);
37 |
38 | map.put(int.class, int.class);
39 | map.put(Integer.class, int.class);
40 |
41 | map.put(long.class, long.class);
42 | map.put(Long.class, long.class);
43 |
44 | map.put(float.class, float.class);
45 | map.put(Float.class, float.class);
46 |
47 | map.put(double.class, double.class);
48 | map.put(Double.class, double.class);
49 |
50 | map.put(char.class, char.class);
51 | map.put(Character.class, char.class);
52 | return map;
53 | }
54 |
55 | private static Map,Class>> wrapperNumberCls() {
56 | Map,Class>> map = new HashMap, Class>>();
57 | map.put(byte.class, Byte.class);
58 | map.put(Byte.class, Byte.class);
59 |
60 | map.put(short.class, Short.class);
61 | map.put(Short.class, Short.class);
62 |
63 | map.put(int.class, Integer.class);
64 | map.put(Integer.class, Integer.class);
65 |
66 | map.put(long.class, Long.class);
67 | map.put(Long.class, Long.class);
68 |
69 | map.put(float.class, Float.class);
70 | map.put(Float.class, Float.class);
71 |
72 | map.put(double.class, Double.class);
73 | map.put(Double.class, Double.class);
74 |
75 | map.put(char.class, Character.class);
76 | map.put(Character.class, Character.class);
77 | return map;
78 | }
79 |
80 | /**
81 | * 是基本类型中的数值类型(包含包装类型)
82 | * @return
83 | */
84 | public static boolean isPrimitiveOrWrapNumber(Class> c){
85 | return numberClassMap.containsKey(c);
86 | }
87 | public static boolean isPrimitiveNumber(Class> c){
88 | if(c == null){
89 | return false;
90 | }
91 | return c.isPrimitive()&&(c!=boolean.class);
92 | // return numberClassMap.containsKey(c);
93 | }
94 |
95 | public static Class> toWrapperClass(Class> c){
96 | return wrapperCls.get(c);
97 | }
98 | public static Class> toPrimitiveClass(Class> c){
99 | return primitiveCls.get(c);
100 | }
101 |
102 | /*
103 | public static void main(String[] args) {
104 | System.out.println((1+"2"+3));
105 | int[] a = new int[]{5,4,3,2,10,100,1};
106 | sort(a);
107 | System.out.println(Arrays.toString(a));
108 | }*/
109 |
110 | public static void sort(int[] array){
111 | for (int i = 1; i < array.length; i++) {
112 | int j = i-1;
113 | int current = array[i];
114 | for(;j>-1&¤t cls,String attr,Class>[] paramTypes){
130 | if(attr == null || "".equals(attr)){
131 | return null;
132 | }
133 | String firstUpper = String.valueOf(attr.charAt(0)).toUpperCase()+attr.substring(1);
134 | Method[] methods = cls.getMethods();
135 |
136 | Method finalMethod = null;
137 | String[] methodNames = new String[]{attr,"get"+firstUpper,"is"+firstUpper};
138 | for (String methodName : methodNames) {
139 | finalMethod = match(methodName, paramTypes, methods);
140 | if(finalMethod!=null){
141 | break;
142 | }
143 | }
144 | return finalMethod;
145 |
146 | /*
147 | String get = "get";
148 | finalMethod = match(get, paramTypes, methods, finalMethod);
149 | if(finalMethod!=null){
150 | return finalMethod;
151 | }*/
152 | }
153 |
154 | public static Method getMethod(Class> cls,String methodName,Class>[] paramTypes){
155 | Method[] methods = cls.getMethods();
156 | return match(methodName,paramTypes,methods);
157 |
158 | }
159 | private static Method match(String methodName, Class>[] paramValueTypes,
160 | Method[] methods) {
161 | Method finalMethod = null;
162 | //方法名称和参数长度核匹配的方法,当不能精确匹配时,返回此方法
163 | Method nameParamLengthEqualsMethod = null;
164 | out:for (Method m : methods) {
165 | String name = m.getName();
166 | if(name.equals(methodName) ){
167 | Class>[] methodParamTypes = m.getParameterTypes();
168 | if(methodParamTypes!=null&& paramValueTypes != null){
169 | if(methodParamTypes.length== paramValueTypes.length){
170 | if(nameParamLengthEqualsMethod == null){
171 | nameParamLengthEqualsMethod = m;
172 | }
173 |
174 | //比较参数是否匹配
175 | for (int i = 0; i < methodParamTypes.length; i++) {
176 | Class> c1 = methodParamTypes[i];
177 | Class> c2 = paramValueTypes[i];
178 | if(!isTypeMatch(c1, c2)){
179 | //如果不匹配,找下一个方法
180 | continue out;
181 | }
182 | }
183 | finalMethod = m;
184 | break;
185 | }
186 | }else if(ArrayUtils.isEmpty(methodParamTypes)&&ArrayUtils.isEmpty(paramValueTypes)){
187 | //如果参数都为null,认为是方法是匹配的
188 | finalMethod = m;
189 | break;
190 | }
191 | }
192 | }
193 | return finalMethod == null?nameParamLengthEqualsMethod:finalMethod;
194 | }
195 |
196 | public static boolean isTypeMatch(Class> c1,Class> c2){
197 | if(c1 == c2||c2==Null.class){
198 | //当c2为Null.class时,表示参数值是null,null值可以与任何类型匹配类型
199 | return true;
200 | }
201 | Class> w1 = ReflectUtil.toWrapperClass(c1);
202 | Class> w2 = ReflectUtil.toWrapperClass(c2);
203 | if(w1!=null){
204 | //可能转换成包装类型
205 | if(w1==w2){
206 | //查看包装类型是否相等
207 | return true;
208 | }
209 | }
210 | //判断c2是不是c1的子类,如果是,返回true
211 | return c1.isAssignableFrom(c2);
212 | }
213 |
214 | static public String getClassName(Class> cls){
215 | if(cls == null){
216 | return "null";
217 | }
218 | return cls.getCanonicalName();
219 | }
220 |
221 |
222 | }
223 |
--------------------------------------------------------------------------------
/src/main/java/com/greenpineyu/fel/common/StringUtils.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.common;
2 |
3 | public class StringUtils {
4 |
5 | /**
6 | * Represents a failed index search.
7 | * @since 2.1
8 | */
9 | public static final int INDEX_NOT_FOUND = -1;
10 |
11 | public static boolean isEmpty(CharSequence cs) {
12 | return cs == null || cs.length() == 0;
13 | }
14 |
15 | /**
16 | * Checks if a CharSequence is not empty ("") and not null.
17 | *
18 | *
19 | * StringUtils.isNotEmpty(null) = false
20 | * StringUtils.isNotEmpty("") = false
21 | * StringUtils.isNotEmpty(" ") = true
22 | * StringUtils.isNotEmpty("bob") = true
23 | * StringUtils.isNotEmpty(" bob ") = true
24 | *
25 | *
26 | * @param cs the CharSequence to check, may be null
27 | * @return {@code true} if the CharSequence is not empty and not null
28 | * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence)
29 | */
30 | public static boolean isNotEmpty(CharSequence cs) {
31 | return !StringUtils.isEmpty(cs);
32 | }
33 |
34 |
35 | /**
36 | * Replaces all occurrences of a String within another String.
37 | *
38 | * A {@code null} reference passed to this method is a no-op.
39 | *
40 | *
41 | * StringUtils.replace(null, *, *) = null
42 | * StringUtils.replace("", *, *) = ""
43 | * StringUtils.replace("any", null, *) = "any"
44 | * StringUtils.replace("any", *, null) = "any"
45 | * StringUtils.replace("any", "", *) = "any"
46 | * StringUtils.replace("aba", "a", null) = "aba"
47 | * StringUtils.replace("aba", "a", "") = "b"
48 | * StringUtils.replace("aba", "a", "z") = "zbz"
49 | *
50 | *
51 | * @see #replace(String text, String searchString, String replacement, int max)
52 | * @param text text to search and replace in, may be null
53 | * @param searchString the String to search for, may be null
54 | * @param replacement the String to replace it with, may be null
55 | * @return the text with any replacements processed,
56 | * {@code null} if null String input
57 | */
58 | public static String replace(String text, String searchString, String replacement) {
59 | return replace(text, searchString, replacement, -1);
60 | }
61 |
62 |
63 | /**
64 | * Replaces a String with another String inside a larger String,
65 | * for the first {@code max} values of the search String.
66 | *
67 | * A {@code null} reference passed to this method is a no-op.
68 | *
69 | *
70 | * StringUtils.replace(null, *, *, *) = null
71 | * StringUtils.replace("", *, *, *) = ""
72 | * StringUtils.replace("any", null, *, *) = "any"
73 | * StringUtils.replace("any", *, null, *) = "any"
74 | * StringUtils.replace("any", "", *, *) = "any"
75 | * StringUtils.replace("any", *, *, 0) = "any"
76 | * StringUtils.replace("abaa", "a", null, -1) = "abaa"
77 | * StringUtils.replace("abaa", "a", "", -1) = "b"
78 | * StringUtils.replace("abaa", "a", "z", 0) = "abaa"
79 | * StringUtils.replace("abaa", "a", "z", 1) = "zbaa"
80 | * StringUtils.replace("abaa", "a", "z", 2) = "zbza"
81 | * StringUtils.replace("abaa", "a", "z", -1) = "zbzz"
82 | *
83 | *
84 | * @param text text to search and replace in, may be null
85 | * @param searchString the String to search for, may be null
86 | * @param replacement the String to replace it with, may be null
87 | * @param max maximum number of values to replace, or {@code -1} if no maximum
88 | * @return the text with any replacements processed,
89 | * {@code null} if null String input
90 | */
91 | public static String replace(String text, String searchString, String replacement, int max) {
92 | if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) {
93 | return text;
94 | }
95 | int start = 0;
96 | int end = text.indexOf(searchString, start);
97 | if (end == INDEX_NOT_FOUND) {
98 | return text;
99 | }
100 | int replLength = searchString.length();
101 | int increase = replacement.length() - replLength;
102 | increase = (increase < 0 ? 0 : increase);
103 | increase *= (max < 0 ? 16 : (max > 64 ? 64 : max));
104 | StringBuilder buf = new StringBuilder(text.length() + increase);
105 | while (end != INDEX_NOT_FOUND) {
106 | buf.append(text.substring(start, end)).append(replacement);
107 | start = end + replLength;
108 | if (--max == 0) {
109 | break;
110 | }
111 | end = text.indexOf(searchString, start);
112 | }
113 | buf.append(text.substring(start));
114 | return buf.toString();
115 | }
116 |
117 |
118 | /**
119 | * Removes all occurrences of a character from within the source string.
120 | *
121 | * A {@code null} source string will return {@code null}.
122 | * An empty ("") source string will return the empty string.
123 | *
124 | *
125 | * StringUtils.remove(null, *) = null
126 | * StringUtils.remove("", *) = ""
127 | * StringUtils.remove("queued", 'u') = "qeed"
128 | * StringUtils.remove("queued", 'z') = "queued"
129 | *
130 | *
131 | * @param str the source String to search, may be null
132 | * @param remove the char to search for and remove, may be null
133 | * @return the substring with the char removed if found,
134 | * {@code null} if null String input
135 | * @since 2.1
136 | */
137 | public static String remove(String str, char remove) {
138 | if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) {
139 | return str;
140 | }
141 | char[] chars = str.toCharArray();
142 | int pos = 0;
143 | for (int i = 0; i < chars.length; i++) {
144 | if (chars[i] != remove) {
145 | chars[pos++] = chars[i];
146 | }
147 | }
148 | return new String(chars, 0, pos);
149 | }
150 |
151 | //-----------------------------------------------------------------------
152 | /**
153 | * Compares two CharSequences, returning {@code true} if they are equal.
154 | *
155 | * {@code null}s are handled without exceptions. Two {@code null}
156 | * references are considered to be equal. The comparison is case sensitive.
157 | *
158 | *
159 | * StringUtils.equals(null, null) = true
160 | * StringUtils.equals(null, "abc") = false
161 | * StringUtils.equals("abc", null) = false
162 | * StringUtils.equals("abc", "abc") = true
163 | * StringUtils.equals("abc", "ABC") = false
164 | *
165 | *
166 | * @see java.lang.String#equals(Object)
167 | * @param cs1 the first CharSequence, may be null
168 | * @param cs2 the second CharSequence, may be null
169 | * @return {@code true} if the CharSequences are equal, case sensitive, or
170 | * both {@code null}
171 | * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence)
172 | */
173 | public static boolean equals(CharSequence cs1, CharSequence cs2) {
174 | return cs1 == null ? cs2 == null : cs1.equals(cs2);
175 | }
176 |
177 | }
178 |
--------------------------------------------------------------------------------
/src/main/java/com/greenpineyu/fel/compile/AbstCompiler.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | import java.io.File;
4 | import java.util.ArrayList;
5 | import java.util.List;
6 | import java.util.concurrent.ExecutorService;
7 | import java.util.concurrent.LinkedBlockingQueue;
8 | import java.util.concurrent.ThreadPoolExecutor;
9 | import java.util.concurrent.TimeUnit;
10 |
11 | import com.greenpineyu.fel.Expression;
12 | import com.greenpineyu.fel.common.StringUtils;
13 |
14 | public abstract class AbstCompiler implements FelCompiler {
15 |
16 | /**
17 | * class文件夹
18 | */
19 | static final String CLASS_DIR;
20 |
21 | private String classpath4compile;
22 |
23 | private static final String BASE_DIR;
24 | static ClassLoader loader;
25 | static {
26 | String userDir = System.getProperty("user.dir");
27 | BASE_DIR = userDir + File.separator + "fel" + File.separator;
28 | CLASS_DIR = BASE_DIR + "classes" + File.separator;
29 | loader = new FileClassLoader(AbstCompiler.class.getClassLoader(),
30 | CLASS_DIR);
31 | createClassDir();
32 | }
33 |
34 | {
35 | classpath4compile = classPathToString();
36 | }
37 |
38 | /**
39 | * Class文件所在文件夹,包含包名
40 | */
41 | static String getClassPackageDir(String pack) {
42 | return CLASS_DIR + packageToPath(pack) + File.separator;
43 | }
44 |
45 | // protected abstract List getClassPath(ClassLoader cl);
46 |
47 | protected String classPathToString() {
48 | List paths = CompileService.getClassPath(this.getClass().getClassLoader());
49 | StringBuilder cpStr = new StringBuilder();
50 | for (String c : paths) {
51 | cpStr.append(c + File.pathSeparator);
52 | }
53 | return cpStr.toString();
54 | }
55 |
56 | static String getSrcPackageDir(String pack) {
57 | return BASE_DIR + "src" + File.separator + packageToPath(pack)
58 | + File.separator;
59 | }
60 |
61 | /*private static String getPath(Class> cls) {
62 | String path = "";
63 | try {
64 | URL location = cls.getProtectionDomain().getCodeSource()
65 | .getLocation();
66 | path = URLDecoder.decode(location.getFile(), "UTF-8");
67 | } catch (UnsupportedEncodingException e) {
68 | }
69 | return path;
70 | }*/
71 |
72 | /*private static String getClassPath() {
73 |
74 | // 将三项添加到classpath 1:lib中的所有jar 2:class目录 3:系统属性:"java.class.path"
75 |
76 | Class> cls = AbstCompiler.class;
77 | String path = getPath(cls);
78 | boolean isJar = path.endsWith(".jar");
79 | Set cpSet = new HashSet();
80 | if (isJar) {
81 | File jarFile = new File(path);
82 | File lib = jarFile.getParentFile();
83 | if (lib != null) {
84 | cpSet.addAll(getLibJars(jarFile.getParent()));
85 | String web_inf = lib.getParent();
86 | String classDir = web_inf + File.separator + "classes";
87 | File classDirfile = new File(classDir);
88 | if (classDirfile != null && classDirfile.exists()) {
89 | cpSet.add(classDir);
90 | }
91 | }
92 | } else {
93 | // String classFullName = cls.getName().replaceAll("\\.", "/");
94 | // int index = path.lastIndexOf(classFullName + ".class");
95 | // if (index != -1) {
96 | // String classDir = path.substring(0, index);
97 | cpSet.add(path);
98 | File classDirFile = new File(path);
99 | File web_inf = classDirFile.getParentFile();
100 | String libDir = web_inf + File.separator + "lib";
101 | cpSet.addAll(getLibJars(libDir));
102 | // }
103 | }
104 | String systemCp = System.getProperty("java.class.path");
105 | if (systemCp != null) {
106 | String[] cps = systemCp.split(File.pathSeparator);
107 | if (cps != null) {
108 | cpSet.addAll(Arrays.asList(cps));
109 | }
110 | }
111 | String cpStr = "";
112 | for (String c : cpSet) {
113 | cpStr += c + File.pathSeparator;
114 | }
115 | return cpStr;
116 | }*/
117 |
118 | /* private static Set getLibJars(String libDir) {
119 | Set jarPathSet = new HashSet();
120 | File dir = new File(libDir);
121 | if (dir != null && dir.isDirectory()) {
122 | File[] files = dir.listFiles(new FilenameFilter() {
123 | public boolean accept(File dir, String name) {
124 | return name.endsWith(".jar");
125 | }
126 | });
127 | for (int i = 0; i < files.length; i++) {
128 | File file = files[i];
129 | String absolutePath = file.getAbsolutePath();
130 | jarPathSet.add(absolutePath);
131 | }
132 | }
133 | return jarPathSet;
134 | }*/
135 |
136 | public Expression compile(JavaSource src) {
137 | Class compile;
138 | try {
139 | compile = this.compileToClass(src);
140 | return compile.newInstance();
141 | } catch (ClassNotFoundException e1) {
142 | e1.printStackTrace();
143 | } catch (InstantiationException e) {
144 | e.printStackTrace();
145 | } catch (IllegalAccessException e) {
146 | e.printStackTrace();
147 | }finally{
148 | String className = src.getName();
149 | String pack = src.getPackageName();
150 | String srcPackageDir = getSrcPackageDir(pack);
151 | clean(srcPackageDir,getClassPackageDir(pack),className);
152 | }
153 | return null;
154 | }
155 |
156 |
157 | abstract Class compileToClass(JavaSource expr)
158 | throws ClassNotFoundException;
159 |
160 | static void createClassDir() {
161 | new File(CLASS_DIR).mkdirs();
162 | }
163 |
164 | private static ExecutorService exeService = initThreadPool();
165 |
166 | private static ExecutorService initThreadPool() {
167 | return new ThreadPoolExecutor(0, 10, 5L, TimeUnit.SECONDS,
168 | new LinkedBlockingQueue());
169 | }
170 |
171 | void clean(final String srcPackageDir,
172 | final String classPackageDir, final String fileName) {
173 | if (exeService.isShutdown()) {
174 | exeService = initThreadPool();
175 | }
176 | exeService.execute(new Runnable() {
177 | public void run() {
178 | // 优先级设置成最低
179 | Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
180 | delFile(srcPackageDir, classPackageDir, fileName);
181 | }
182 | });
183 | // exeService.shutdown();
184 | }
185 |
186 | void delFile(final String srcPackageDir, final String classPackageDir,
187 | final String fileName) {
188 | String src = srcPackageDir + fileName + ".java";
189 | deleteFile(src);
190 | String cls = classPackageDir + fileName + ".class";
191 | deleteFile(cls);
192 | }
193 |
194 | void deleteFile(String src) {
195 | File file = new File(src);
196 | // System.out.println("delete file:"+src);
197 | if (file.exists()) {
198 | file.delete();
199 | }
200 | }
201 |
202 |
203 | List getCompileOption() {
204 | List options = new ArrayList();
205 | options.add("-encoding");
206 | options.add("UTF-8");
207 | options.add("-d");
208 | options.add(CLASS_DIR);
209 |
210 | if (StringUtils.isNotEmpty(classpath4compile)) {
211 | options.add("-classpath");
212 | options.add(classpath4compile);
213 | }
214 | return options;
215 | }
216 |
217 | /**
218 | * 将包名转换成包路径
219 | *
220 | * @param packageName
221 | * @return
222 | */
223 | private static String packageToPath(String packageName) {
224 | String sep = File.separator;
225 | // if (sep.equals("\\")) {
226 | // sep = "\\\\";
227 | // }
228 | return StringUtils.replace(packageName, ".", sep);
229 | // return packageName.replaceAll("\\.", sep);
230 | }
231 |
232 | }
233 |
--------------------------------------------------------------------------------
/src/main/java/com/greenpineyu/fel/compile/CompileService.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | import java.io.IOException;
4 | import java.net.URL;
5 | import java.net.URLClassLoader;
6 | import java.util.ArrayList;
7 | import java.util.Enumeration;
8 | import java.util.List;
9 |
10 | import com.greenpineyu.fel.Expression;
11 | import com.greenpineyu.fel.context.FelContext;
12 | import com.greenpineyu.fel.parser.FelNode;
13 |
14 | public class CompileService {
15 |
16 | private SourceGenerator srcGen;
17 | private FelCompiler complier;
18 |
19 | public SourceGenerator getSrcGen() {
20 | return srcGen;
21 | }
22 |
23 | public void setSrcGen(SourceGenerator srcGen) {
24 | this.srcGen = srcGen;
25 | }
26 |
27 | public FelCompiler getComplier() {
28 | return complier;
29 | }
30 |
31 | public void setComplier(FelCompiler complier) {
32 | this.complier = complier;
33 | }
34 |
35 | {
36 | srcGen = new SourceGeneratorImpl();
37 | String name = getCompilerClassName();
38 | FelCompiler comp = newCompiler(name);
39 | complier = comp;
40 | }
41 |
42 | public static List getClassPath(ClassLoader cl) {
43 | List paths = new ArrayList();
44 | while (cl != null) {
45 | boolean isUrlClassloader = cl instanceof URLClassLoader;
46 | if (isUrlClassloader) {
47 | URLClassLoader urlClassLoader = (URLClassLoader) cl;
48 | for (URL url : urlClassLoader.getURLs()) {
49 | paths.add(url.getFile());
50 | }
51 | } else {
52 | Enumeration resources = null;
53 | try {
54 | resources = cl.getResources("/");
55 | } catch (IOException e) {
56 | e.printStackTrace();
57 | }
58 | if (resources != null) {
59 | while (resources.hasMoreElements()) {
60 | URL resource = resources.nextElement();
61 | paths.add(resource.getFile());
62 | }
63 | }
64 | }
65 | cl = cl.getParent();
66 | }
67 | return paths;
68 | }
69 |
70 | private FelCompiler newCompiler(String name) {
71 | FelCompiler comp = null;
72 | try {
73 | @SuppressWarnings("unchecked")
74 | Class cls = (Class) Class.forName(name);
75 | comp = cls.newInstance();
76 | } catch (ClassNotFoundException e) {
77 | e.printStackTrace();
78 | } catch (InstantiationException e) {
79 | e.printStackTrace();
80 | } catch (IllegalAccessException e) {
81 | e.printStackTrace();
82 | } finally {
83 | }
84 | return comp;
85 | }
86 |
87 | private String getCompilerClassName() {
88 | String version = System.getProperty("java.version");
89 | String compileClassName = FelCompiler.class.getName();
90 | if (version != null && version.startsWith("1.5")) {
91 | compileClassName += "15";
92 | } else {
93 | compileClassName += "16";
94 | }
95 | return compileClassName;
96 | }
97 |
98 | public Expression compile(FelContext ctx, FelNode node, String originalExp) {
99 | try {
100 | JavaSource src = srcGen.getSource(ctx, node);
101 | if (src instanceof ConstExpSrc) {
102 | ConstExpSrc s = (ConstExpSrc) src;
103 | return s.getValue();
104 | }
105 | src.setSource("// 表达式:" + originalExp + "\n" + src.getSource());
106 | // System.out.println("****************\n" + src.getSource());
107 | return complier.compile(src);
108 | } catch (Exception e) {
109 | e.printStackTrace();
110 | }
111 | return null;
112 | }
113 |
114 | public static void main(String[] args) {
115 | System.getProperties().list(System.out);
116 | }
117 |
118 | }
119 |
--------------------------------------------------------------------------------
/src/main/java/com/greenpineyu/fel/compile/ConstExp.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | import com.greenpineyu.fel.Expression;
4 | import com.greenpineyu.fel.context.FelContext;
5 |
6 | public final class ConstExp implements Expression {
7 | public ConstExp(Object o) {
8 | this.value = o;
9 | }
10 |
11 | private final Object value;
12 |
13 | public final Object eval(FelContext context) {
14 | return value;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/greenpineyu/fel/compile/ConstExpSrc.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | /**
4 | * @author yuqingsong
5 | *
6 | */
7 | public class ConstExpSrc extends JavaSource {
8 |
9 | public ConstExpSrc(Object o) {
10 | this.value = new ConstExp(o);
11 | }
12 |
13 | private final ConstExp value;
14 |
15 | public ConstExp getValue() {
16 | return value;
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/com/greenpineyu/fel/compile/FelCompiler.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | import com.greenpineyu.fel.Expression;
4 |
5 | public interface FelCompiler {
6 |
7 | /**
8 | *
9 | * 编译代码,并创建Expression
10 | * @param expr
11 | * @return
12 | */
13 | public Expression compile(JavaSource src);
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/greenpineyu/fel/compile/FelCompiler16.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.net.URI;
6 | import java.net.URISyntaxException;
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | import javax.tools.DiagnosticCollector;
11 | import javax.tools.FileObject;
12 | import javax.tools.ForwardingJavaFileManager;
13 | import javax.tools.JavaCompiler;
14 | import javax.tools.JavaCompiler.CompilationTask;
15 | import javax.tools.JavaFileManager;
16 | import javax.tools.JavaFileObject;
17 | import javax.tools.JavaFileObject.Kind;
18 | import javax.tools.StandardJavaFileManager;
19 | import javax.tools.StandardLocation;
20 | import javax.tools.ToolProvider;
21 |
22 | import com.greenpineyu.fel.Expression;
23 | import com.greenpineyu.fel.exception.CompileException;
24 |
25 | public class FelCompiler16 implements FelCompiler {
26 | private final FelCompilerClassloader classLoader;
27 |
28 | private final JavaCompiler compiler;
29 |
30 | private final List options;
31 |
32 | private DiagnosticCollector diagnostics;
33 |
34 | private final JavaFileManager javaFileManager;
35 |
36 | public FelCompiler16() {
37 | compiler = ToolProvider.getSystemJavaCompiler();
38 |
39 | if (compiler == null) {
40 | throw new IllegalStateException(
41 | "Cannot find the system Java compiler. "
42 | + "Check that your class path includes tools.jar");
43 | }
44 |
45 | this.classLoader = new FelCompilerClassloader(this.getClass()
46 | .getClassLoader());
47 | diagnostics = new DiagnosticCollector();
48 | final StandardJavaFileManager fileManager = compiler
49 | .getStandardFileManager(diagnostics, null, null);
50 |
51 | ClassLoader loader = this.classLoader.getParent();
52 | List paths = CompileService.getClassPath(loader);
53 | List cpFiles = new ArrayList();
54 | if (paths != null && (!paths.isEmpty())) {
55 | for (String file : paths) {
56 | cpFiles.add(new File(file));
57 | }
58 | }
59 | try {
60 | fileManager.setLocation(StandardLocation.CLASS_PATH, cpFiles);
61 | } catch (IOException e) {
62 | e.printStackTrace();
63 | }
64 |
65 | /*
66 |
67 |
68 | if (loader instanceof URLClassLoader
69 | && (!loader.getClass().getName()
70 | .equals("sun.misc.Launcher$AppClassLoader"))) {
71 | System.out.println("..............................asdfasdf......................");
72 | try {
73 | URLClassLoader urlClassLoader = (URLClassLoader) loader;
74 | List path = new ArrayList();
75 | for (URL url : urlClassLoader.getURLs()) {
76 | File file = new File(url.getFile());
77 | path.add(file);
78 | }
79 | fileManager.setLocation(StandardLocation.CLASS_PATH, path);
80 | } catch (IOException e) {
81 | e.printStackTrace();
82 | }
83 | } else {
84 | Enumeration resources = null;
85 | try {
86 | resources = loader.getResources("/");
87 | } catch (IOException e) {
88 | e.printStackTrace();
89 | }
90 | if (resources != null) {
91 | List path = new ArrayList();
92 | while (resources.hasMoreElements()) {
93 | URL resource = resources.nextElement();
94 | File file = new File(resource.getFile());
95 | path.add(file);
96 | }
97 | }
98 |
99 | }*/
100 |
101 | javaFileManager = new ForwardingJavaFileManager(
102 | fileManager) {
103 | @Override
104 | public JavaFileObject getJavaFileForOutput(Location location,
105 | String qualifiedName, Kind kind, FileObject outputFile)
106 | throws IOException {
107 | // 由于编译成功后的bytecode需要放到file中,所以需要将file放到classloader中,以便读取bytecode生成Class对象.
108 | classLoader.add(qualifiedName, outputFile);
109 | return (JavaFileObject) outputFile;
110 | }
111 | };
112 | this.options = new ArrayList();
113 | // this.options.add("-O");
114 | }
115 |
116 | public Expression compile(JavaSource src) {
117 |
118 | Class compile = compileToClass(src);
119 | try {
120 | return (Expression) compile.newInstance();
121 | } catch (InstantiationException e) {
122 | e.printStackTrace();
123 | } catch (IllegalAccessException e) {
124 | e.printStackTrace();
125 | }
126 | return null;
127 | }
128 |
129 |
130 | public synchronized Class compileToClass(final JavaSource src) {
131 | List compileSrcs = new ArrayList();
132 | String className = src.getSimpleName();
133 | final FelJavaFileObject compileSrc = new FelJavaFileObject(className,
134 | src.getSource());
135 | compileSrcs.add(compileSrc);
136 | final CompilationTask task = compiler.getTask(null, javaFileManager,
137 | diagnostics, options, null, compileSrcs);
138 | final Boolean result = task.call();
139 | if (result == null || !result.booleanValue()) {
140 | // diagnostics.
141 | // 编译失败
142 | // diagnostics.getDiagnostics()
143 | throw new CompileException(src.getSource() + "\n"
144 | + diagnostics.getDiagnostics().toString());
145 | }
146 | try {
147 | return loadClass(src.getName());
148 | } catch (ClassNotFoundException e) {
149 | e.printStackTrace();
150 | }
151 | return null;
152 | }
153 |
154 | @SuppressWarnings("unchecked")
155 | public Class loadClass(final String qualifiedClassName)
156 | throws ClassNotFoundException {
157 | return (Class) classLoader.loadClass(qualifiedClassName);
158 | }
159 |
160 | static URI toUri(String name) {
161 | try {
162 | return new URI(name);
163 | } catch (URISyntaxException e) {
164 | throw new RuntimeException(e);
165 | }
166 | }
167 |
168 | }
169 |
170 |
--------------------------------------------------------------------------------
/src/main/java/com/greenpineyu/fel/compile/FelCompilerClassloader.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | import javax.tools.FileObject;
7 |
8 | public final class FelCompilerClassloader extends ClassLoader {
9 | private final Map compileFileMap = new HashMap();
10 |
11 | public FelCompilerClassloader(ClassLoader parentClassLoader) {
12 | super(parentClassLoader);
13 | }
14 |
15 |
16 | @Override
17 | protected synchronized Class> findClass(String qualifiedClassName) throws ClassNotFoundException {
18 | FileObject file = compileFileMap.remove(qualifiedClassName);
19 | if (file != null) {
20 | byte[] bytes = ((FelJavaFileObject) file).getByteCode();
21 | return defineClass(qualifiedClassName, bytes, 0, bytes.length);
22 | }
23 | return super.findClass(qualifiedClassName);
24 | }
25 |
26 | public void add(String qualifiedClassName, final FileObject javaFile) {
27 | compileFileMap.put(qualifiedClassName, javaFile);
28 | }
29 |
30 | }
--------------------------------------------------------------------------------
/src/main/java/com/greenpineyu/fel/compile/FelJavaFileObject.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | import java.io.ByteArrayInputStream;
4 | import java.io.ByteArrayOutputStream;
5 | import java.io.InputStream;
6 | import java.io.OutputStream;
7 | import java.net.URI;
8 |
9 | import javax.tools.SimpleJavaFileObject;
10 |
11 | /**
12 | * 编译时,用于提供类源码和保存类的字节码
13 | *
14 | * @author yuqingsong
15 | *
16 | */
17 | public class FelJavaFileObject extends SimpleJavaFileObject {
18 |
19 | // If kind == CLASS, this stores byte code from openOutputStream
20 | private final ByteArrayOutputStream byteCodeOs = new ByteArrayOutputStream();
21 |
22 | // if kind == SOURCE, this contains the source text
23 | private final CharSequence src;
24 |
25 | public FelJavaFileObject(final String baseName, final CharSequence source) {
26 | super(FelCompiler16.toUri(baseName + ".java"),
27 | Kind.SOURCE);
28 | this.src = source;
29 | }
30 |
31 | FelJavaFileObject(final String name, final Kind kind) {
32 | super(FelCompiler16.toUri(name), kind);
33 | src = null;
34 | }
35 |
36 | public FelJavaFileObject(URI uri, Kind kind) {
37 | super (uri, kind);
38 | src = null;
39 | }
40 |
41 | @Override
42 | public CharSequence getCharContent(final boolean ignoreEncodingErrors) throws UnsupportedOperationException {
43 | if (src == null) {
44 | throw new UnsupportedOperationException();
45 | }
46 |
47 | return src;
48 | }
49 |
50 | @Override
51 | public InputStream openInputStream() {
52 | return new ByteArrayInputStream(getByteCode());
53 | }
54 |
55 | @Override
56 | public OutputStream openOutputStream() {
57 | return byteCodeOs;
58 | }
59 |
60 | byte[] getByteCode() {
61 | return byteCodeOs.toByteArray();
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/com/greenpineyu/fel/compile/FelMethod.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | import com.greenpineyu.fel.context.FelContext;
4 | import com.greenpineyu.fel.parser.FelNode;
5 |
6 | /**
7 | *
8 | */
9 | public class FelMethod implements SourceBuilder {
10 |
11 | private Class> returnType;
12 |
13 | private String code;
14 |
15 |
16 | public FelMethod(Class> returnType,String code){
17 | this.returnType = returnType;
18 | this.code = code;
19 | }
20 |
21 |
22 | public Class> returnType(FelContext ctx, FelNode node) {
23 | return returnType;
24 | }
25 |
26 |
27 | public void setReturnType(Class> returnType) {
28 | this.returnType = returnType;
29 | }
30 |
31 |
32 | public String source(FelContext ctx, FelNode node) {
33 | return code;
34 | }
35 |
36 |
37 | public void setCode(String code) {
38 | this.code = code;
39 | }
40 |
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/greenpineyu/fel/compile/FileClassLoader.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | import java.io.ByteArrayOutputStream;
4 | import java.io.File;
5 | import java.io.FileInputStream;
6 | import java.io.IOException;
7 |
8 | public class FileClassLoader extends ClassLoader {
9 | private String dir;
10 | public static final String fileType = ".class";
11 |
12 | public FileClassLoader(ClassLoader arg0, String dir) {
13 | super(arg0);
14 | this.dir = dir;
15 | }
16 |
17 | public Class> findClass(String name) {
18 | byte[] data = loadClassData(name);
19 | return defineClass(name, data, 0, data.length);
20 | }
21 |
22 | public byte[] loadClassData(String name) {
23 | name = name.replaceAll("\\.", "/");
24 | FileInputStream fis = null;
25 | byte[] data = null;
26 | try {
27 | fis = new FileInputStream(new File(dir + name + fileType));
28 | ByteArrayOutputStream baos = new ByteArrayOutputStream();
29 | int ch = 0;
30 | while ((ch = fis.read()) != -1) {
31 | baos.write(ch);
32 | }
33 | data = baos.toByteArray();
34 | } catch (IOException e) {
35 | e.printStackTrace();
36 | }finally{
37 | if(fis!= null){
38 | try {
39 | fis.close();
40 | } catch (IOException e) {
41 | e.printStackTrace();
42 | }
43 | }
44 | }
45 | return data;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/com/greenpineyu/fel/compile/InterpreterSourceBuilder.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | import com.greenpineyu.fel.context.AbstractContext;
4 | import com.greenpineyu.fel.context.FelContext;
5 | import com.greenpineyu.fel.interpreter.Interpreter;
6 | import com.greenpineyu.fel.parser.FelNode;
7 |
8 | public class InterpreterSourceBuilder implements SourceBuilder {
9 |
10 |
11 |
12 |
13 | private static final SourceBuilder instance;
14 |
15 | public static SourceBuilder getInstance() {
16 | return instance;
17 | }
18 |
19 | static{
20 | instance = new InterpreterSourceBuilder();
21 | }
22 |
23 |
24 |
25 | public Class> returnType(FelContext ctx, FelNode node) {
26 | return AbstractContext.getVarType(node.getInterpreter().interpret(ctx, node));
27 | }
28 |
29 | /**
30 | * 用户自定义解析器生成的java代码
31 | *
32 | * @param ctx
33 | * @param node
34 | * @return
35 | */
36 | public String source(FelContext ctx, FelNode node) {
37 | // 用户设置了解释器
38 | // Interpreter inte = new ProxyInterpreter(node.getInterpreter(), node);
39 | Interpreter inte = node.getInterpreter();
40 | SourceBuilder nodeBuilder = node.toMethod(ctx);
41 | Class> type =nodeBuilder.returnType(ctx, node);
42 | String code = "("+type.getName()+")";
43 | String varName = VarBuffer.push(inte,Interpreter.class);
44 | String nodeVarName = VarBuffer.push(node, FelNode.class);
45 | code += varName + ".interpret(context," + nodeVarName + ")";
46 | boolean isNumber = Number.class.isAssignableFrom(type);
47 | if(isNumber){
48 | code="("+code+").doubleValue()";
49 | }
50 | return code;
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/com/greenpineyu/fel/compile/JavaSource.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | public class JavaSource {
4 |
5 | /**
6 | * 类名,不包含包名
7 | */
8 | private String simpleName;
9 |
10 | /**
11 | * java源码
12 | */
13 | private String source;
14 |
15 | /**
16 | * 包名
17 | */
18 | private String packageName;
19 |
20 | public String getPackageName() {
21 | return packageName;
22 | }
23 |
24 | public void setPackageName(String packageName) {
25 | this.packageName = packageName;
26 | }
27 |
28 | public String getSimpleName() {
29 | return simpleName;
30 | }
31 |
32 | public void setSimpleName(String name) {
33 | this.simpleName = name;
34 | }
35 |
36 | public String getName(){
37 | return packageName + "." + simpleName;
38 | }
39 |
40 | public String getSource() {
41 | return source;
42 | }
43 |
44 | public void setSource(String source) {
45 | this.source = source;
46 | }
47 |
48 |
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/com/greenpineyu/fel/compile/SourceBuilder.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | import com.greenpineyu.fel.context.FelContext;
4 | import com.greenpineyu.fel.parser.FelNode;
5 |
6 | /**
7 | * 创建java源码接口,此接口和SourceGenerator的区别在于,后者负责创建整个java类的源码。前者只用了创建表达式的代码片断。
8 | * @author yuqingsong
9 | *
10 | */
11 | public interface SourceBuilder {
12 |
13 | /**
14 | * 类型
15 | * @param ctx TODO
16 | * @param node TODO
17 | * @return
18 | */
19 | Class> returnType(FelContext ctx, FelNode node);
20 | /**
21 | * 构建源码
22 | * @param node TODO
23 | * @return
24 | */
25 | String source(FelContext ctx, FelNode node);
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/com/greenpineyu/fel/compile/SourceGenerator.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | import com.greenpineyu.fel.context.FelContext;
4 | import com.greenpineyu.fel.optimizer.Optimizer;
5 | import com.greenpineyu.fel.parser.FelNode;
6 |
7 | public interface SourceGenerator {
8 |
9 | /**
10 | * 获取表达式JAVA源代码
11 | * @param node TODO
12 | * @return
13 | */
14 | JavaSource getSource(FelContext ctx, FelNode node);
15 |
16 | void addOpti(Optimizer opti);
17 |
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/com/greenpineyu/fel/compile/SourceGeneratorImpl.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 | import java.io.InputStreamReader;
7 | import java.util.ArrayList;
8 | import java.util.Collection;
9 | import java.util.HashMap;
10 | import java.util.List;
11 | import java.util.Map;
12 |
13 | import com.greenpineyu.fel.Expression;
14 | import com.greenpineyu.fel.FelEngine;
15 | import com.greenpineyu.fel.FelEngineImpl;
16 | import com.greenpineyu.fel.common.Callable;
17 | import com.greenpineyu.fel.common.ReflectUtil;
18 | import com.greenpineyu.fel.common.StringUtils;
19 | import com.greenpineyu.fel.context.FelContext;
20 | import com.greenpineyu.fel.optimizer.ConstExpOpti;
21 | import com.greenpineyu.fel.optimizer.ConstOpti;
22 | import com.greenpineyu.fel.optimizer.Optimizer;
23 | import com.greenpineyu.fel.parser.AbstFelNode;
24 | import com.greenpineyu.fel.parser.ConstNode;
25 | import com.greenpineyu.fel.parser.FelNode;
26 | import com.greenpineyu.fel.parser.VarAstNode;
27 |
28 | public class SourceGeneratorImpl implements SourceGenerator {
29 |
30 | private List opt;
31 |
32 | private static String template;
33 |
34 | private static int count = 0;
35 |
36 | private Map localvars;
37 |
38 | /**
39 | * 包名
40 | */
41 | static final String PACKAGE;
42 |
43 | {
44 | opt = new ArrayList();
45 | localvars = new HashMap();
46 | initOpti();
47 | }
48 |
49 | static {
50 | String fullName = SourceGeneratorImpl.class.getName();
51 | PACKAGE = fullName.substring(0, fullName.lastIndexOf("."));
52 |
53 | StringBuilder sb = new StringBuilder();
54 | InputStream in = SourceGeneratorImpl.class
55 | .getResourceAsStream("java.template");
56 | BufferedReader reader = new BufferedReader(new InputStreamReader(in));
57 | String line = null;
58 | try {
59 | while ((line = reader.readLine()) != null) {
60 | sb.append(line).append("\r\n");
61 | }
62 | } catch (IOException e) {
63 | e.printStackTrace();
64 | }
65 | template = sb.toString();
66 | }
67 |
68 | public JavaSource getSource(FelContext ctx, FelNode node) {
69 |
70 | String src = "";
71 | String className = getClassName();
72 | synchronized(this){
73 | node = optimize(ctx, node);
74 | if (node instanceof ConstNode) {
75 | ConstNode n = (ConstNode) node;
76 | return new ConstExpSrc(n.interpret(null, null));
77 | }
78 | SourceBuilder builder = node.toMethod(ctx);
79 | String exp = builder.source(ctx, node);
80 | src = buildsource(exp, className);
81 | this.localvars.clear();
82 | }
83 | // System.out.println("****************\n" + src);
84 | JavaSource returnMe = new JavaSource();
85 | returnMe.setSimpleName(className);
86 | returnMe.setSource(src);
87 | returnMe.setPackageName(PACKAGE);
88 | return returnMe;
89 | }
90 |
91 | private String buildsource(String expression, String className) {
92 | String src = StringUtils.replace(template,"${classname}", className);
93 | // src = src.replaceAll("\\$\\{extends\\}", "Object");
94 | StringBuilder attrs = new StringBuilder();
95 | String pop = VarBuffer.pop();
96 | if (pop != null) {
97 | // 第一行不需要添加空格
98 | attrs.append(pop).append("\r\n");
99 | pop = VarBuffer.pop();
100 | }
101 | while(pop!=null){
102 | attrs.append(" ").append(pop).append("\r\n");
103 | pop = VarBuffer.pop();
104 | }
105 | // removeLastEnter(attrs);
106 | src = StringUtils.replace(src, "${attrs}", attrs.toString());
107 | src = StringUtils.replace(src, "${localVars}", getLocalVarsCode());
108 | src = StringUtils.replace(src, "${expression}", expression);
109 | // src = src.replaceAll("\\$\\{attrs\\}", attrs.toString());
110 | // src = src.replaceAll("\\$\\{localVars\\}", getLocalVarsCode());
111 | // src = src.replaceAll("\\$\\{expression\\}", expression);
112 | return src;
113 | }
114 |
115 | private String getClassName() {
116 | String className = null;
117 | synchronized (SourceGeneratorImpl.class) {
118 | className = "Fel_" + count++;
119 | }
120 | return className;
121 | }
122 |
123 | private String getLocalVarsCode() {
124 | StringBuilder sb = new StringBuilder();
125 | Collection values = localvars.values();
126 | boolean isFirst = true;
127 | for (StringKeyValue code : values) {
128 | if (isFirst) {
129 | // 第一行不需要添加空格
130 | isFirst = false;
131 | } else {
132 | sb.append(" ");
133 | }
134 | sb.append(code.value).append("\r\n");
135 | }
136 | removeLastEnter(sb);
137 | return sb.toString();
138 | }
139 |
140 | private void removeLastEnter(StringBuilder sb) {
141 | if(sb.length()>0){
142 | sb.delete(sb.length()-2, sb.length());
143 | }
144 | }
145 |
146 | // private final int localVarCount = 0;
147 |
148 | /*
149 | * private String getLocalVarName() { String varName = null; synchronized
150 | * (SourceGeneratorImpl.class) { varName = "var_" + localVarCount++; }
151 | * return varName; }
152 | */
153 |
154 | class StringKeyValue {
155 | String key;
156 | String value;
157 |
158 | public StringKeyValue(String key, String value) {
159 | this.key = key;
160 | this.value = value;
161 | }
162 | }
163 |
164 | /**
165 | * 对节点进行优化
166 | *
167 | * @param ctx
168 | * @param node
169 | * @return
170 | */
171 | private FelNode optimize(FelContext ctx, FelNode node) {
172 | for (Optimizer o : opt) {
173 | node = o.call(ctx, node);
174 | }
175 | return node;
176 | }
177 |
178 | private void initOpti() {
179 | // 进行常量优化(计算表达式中的常量节点)
180 | Optimizer constOpti = new ConstOpti();
181 | this.addOpti(constOpti);
182 |
183 | // 如果整个表达式是一个常量,再进行一次优化(可以减少装包拆包花费的时间)
184 | Optimizer constExpOpti = new ConstExpOpti();
185 |
186 | this.addOpti(constExpOpti);
187 |
188 |
189 | // 进行变量优化
190 | Optimizer optimizVars = getVarOpti();
191 | this.addOpti(optimizVars);
192 | }
193 |
194 | public static final Callable varsFilter = new Callable() {
195 | public Boolean call(FelNode... node) {
196 | FelNode n = node[0];
197 | return VarAstNode.isVar(n);
198 | }
199 | };
200 |
201 | /**
202 | * 获取变量优化方案
203 | *
204 | * @return
205 | */
206 | private Optimizer getVarOpti() {
207 | Optimizer optimizVars = new Optimizer() {
208 | public FelNode call(FelContext ctx, FelNode node) {
209 | List nodes = AbstFelNode.getNodes(node,varsFilter);
210 | // 多次出现的变量
211 | // List repeatNodes = new ArrayList();
212 |
213 | Map> repeatNodeMap = new HashMap>();
214 | for (FelNode n : nodes) {
215 | String name = n.getText();
216 | List repeatNodes = repeatNodeMap.get(name);
217 | if(repeatNodes == null){
218 | repeatNodes = new ArrayList();
219 | repeatNodeMap.put(name, repeatNodes);
220 | }
221 | repeatNodes.add(n);
222 | // if(count != null){
223 | // repeatNodes.add(n);
224 | // count.increment();
225 | // }else{
226 | // count = new MutableInt(1);
227 | // varCount.put(name, count);
228 | // }
229 | }
230 | for (List repeatNodes : repeatNodeMap.values()) {
231 | if(repeatNodes.size()>1){
232 | for (FelNode n : repeatNodes) {
233 | n.setSourcebuilder(getVarSrcBuilder(n.toMethod(ctx)));
234 | }
235 | }
236 | }
237 |
238 | return node;
239 | }
240 |
241 | /**
242 | * 修改变量的代码生成方式
243 | *
244 | * @param ctx
245 | * @param node
246 | */
247 | @SuppressWarnings("unused")
248 | private void setVarSourceBuilder(FelContext ctx, FelNode node) {
249 | if (node instanceof VarAstNode) {
250 | node.setSourcebuilder(getVarSrcBuilder(node.toMethod(ctx)));
251 | } else {
252 | List children = node.getChildren();
253 | if (children != null && !children.isEmpty()) {
254 | for (FelNode child : children) {
255 | setVarSourceBuilder(ctx, child);
256 | }
257 | }
258 |
259 | }
260 | }
261 |
262 | private SourceBuilder getVarSrcBuilder(final SourceBuilder old) {
263 |
264 | return new SourceBuilder() {
265 |
266 | public String source(FelContext ctx, FelNode node) {
267 | String text = node.getText();
268 | if (localvars.containsKey(text)) {
269 | StringKeyValue kv = localvars.get(text);
270 | return kv.key;
271 | }
272 | // String varName = getLocalVarName();
273 | String varName = text;
274 | Class> type = this.returnType(ctx, node);
275 | String declare = "";
276 | String typeDeclare = type.getCanonicalName();
277 | if(ReflectUtil.isPrimitiveOrWrapNumber(type)){
278 | Class> primitiveClass = ReflectUtil.toPrimitiveClass(type);
279 | typeDeclare = primitiveClass.getSimpleName();
280 | }else if (Number.class.isAssignableFrom(type)) {
281 | typeDeclare = "double";
282 | }
283 |
284 | declare = typeDeclare + " " + varName + " = "
285 | + old.source(ctx, node) + "; //" + text;
286 | StringKeyValue kv = new StringKeyValue(varName, declare);
287 | localvars.put(text, kv);
288 | return varName;
289 | }
290 |
291 | public Class> returnType(FelContext ctx, FelNode n) {
292 | // VarAstNode node = (VarAstNode) old;
293 | return old.returnType(ctx, n);
294 | }
295 | };
296 | }
297 | };
298 | return optimizVars;
299 | }
300 |
301 | public void addOpti(Optimizer opti) {
302 | this.opt.add(opti);
303 | }
304 |
305 | public static void main(String[] args) {
306 | FelEngine engine = new FelEngineImpl();
307 | FelContext ctx = engine.getContext();
308 | ctx.set("i", 100);
309 | ctx.set("pi", 3.14f);
310 | String exp = "pi*i*i*pi";
311 | Expression expObj = engine.compile(exp, ctx);
312 | Object eval = expObj.eval(ctx);
313 | // cost(ctx, new Abcd());
314 | cost(ctx, expObj);
315 | System.out.println(eval);
316 | }
317 |
318 | private static void cost(FelContext ctx, Expression expObj) {
319 | int count = 10*1000*1000;
320 | long start = System.currentTimeMillis();
321 | for (int i = 0; i < count; i++) {
322 | expObj.eval(ctx);
323 | }
324 | long end = System.currentTimeMillis();
325 | System.out.println(end-start);
326 | }
327 | }
328 |
329 |
--------------------------------------------------------------------------------
/src/main/java/com/greenpineyu/fel/compile/VarBuffer.java:
--------------------------------------------------------------------------------
1 | package com.greenpineyu.fel.compile;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 | import java.util.Stack;
6 | import java.util.UUID;
7 | import java.util.concurrent.ExecutorService;
8 | import java.util.concurrent.Executors;
9 |
10 |
11 | public class VarBuffer {
12 | static private ThreadLocal> varCodes;
13 | static private ThreadLocal