1 // Copyright 2006-2007 all rights reserved; see LICENSE file for BSD-style license
3 package edu.berkeley.sbp.misc;
4 import edu.berkeley.sbp.*;
5 import edu.berkeley.sbp.util.*;
8 import java.lang.reflect.*;
10 /** use of this class is not recommended; it can handle only S-attributed grammars */
11 public class ReflectiveWalker extends StringWalker {
12 public ReflectiveWalker() { this.target = this; }
13 public ReflectiveWalker(Object target) { this.target = target; }
14 private final Object target;
15 public static String mangle(String s) {
16 StringBuffer ret = new StringBuffer();
17 for(int i=0; i<s.length(); i++) {
19 if (i==0 && c >= '0' && c <= '9') { ret.append('_'); ret.append(c); continue; }
21 case ' ': ret.append("_space_"); break;
22 case '~': ret.append("_tilde_"); break;
23 case ';': ret.append("_semicolon_"); break;
24 case '=': ret.append("_equals_"); break;
25 case '-': ret.append("_minus_"); break;
26 case ')': ret.append("_rightparen_"); break;
27 case '(': ret.append("_leftparen_"); break;
28 case '!': ret.append("_bang_"); break;
29 case '`': ret.append("_backtick_"); break;
30 case '\"': ret.append("_quotes_"); break;
31 case '\'': ret.append("_quote_"); break;
32 case ',': ret.append("_comma_"); break;
33 case '.': ret.append("_dot_"); break;
34 case '>': ret.append("_greater_"); break;
35 case '<': ret.append("_less_"); break;
36 case '&': ret.append("_amp_"); break;
37 case '@': ret.append("_at_"); break;
38 case '#': ret.append("_hash_"); break;
39 case '|': ret.append("_pipe_"); break;
40 case '^': ret.append("_caret_"); break;
41 case '%': ret.append("_percent_"); break;
42 case '$': ret.append("_dollar_"); break;
43 case ':': ret.append("_colon_"); break;
44 case '?': ret.append("_question_"); break;
45 case '/': ret.append("_slash_"); break;
46 case '\\': ret.append("_backslash_"); break;
47 case '*': ret.append("_star_"); break;
48 case '+': ret.append("_plus_"); break;
49 case '_': ret.append("_underscore_"); break;
50 case '[': ret.append("_leftbracket_"); break;
51 case ']': ret.append("_rightbracket_"); break;
52 case '{': ret.append("_leftbrace_"); break;
53 case '}': ret.append("_rightbrace_"); break;
54 default: ret.append(c); break;
57 return ret.toString();
60 public Object walk(Tree<String> tree) {
61 if (tree.head()!=null) {
62 Member m = member("$"+mangle(tree.head()), 0, false);
64 if ((m instanceof Method) && ((Method)m).getReturnType()==Void.TYPE) {
65 Reflection.fuzzyInvoke(target, m, new Object[0]);
69 return super.walk(tree);
72 public void walk(String tag) {
73 if (tag==null) return;
74 Member m = member(mangle(tag), 0, false);
75 if (m!=null) Reflection.fuzzyInvoke(target, m);
77 protected Object defaultWalk(String tag, Object[] argo) { return super.walk(tag, argo); }
78 public Object walk(String tag, Object[] argo) {
79 if (argo.length==0) return super.walk(tag, argo);
80 if (argo==null) return tag;
81 if (tag==null || "".equals(tag)) return argo;
82 Member m = tag==null ? null : member(mangle(tag), argo.length, false);
83 if (m==null) return defaultWalk(tag, argo);
84 //System.out.println("preparing to invoke method " + (m==null ? "null" : (m.toString())) + " for sequence " + (owner()+"."+tag));
85 if (m != null) return Reflection.fuzzyInvoke(target, m, argo);
86 if (argo.length==0) return null;
87 if (argo.length==1) return argo[0];
88 Class c = argo[0].getClass();
89 for(Object o : argo) c = Reflection.lub(c, o.getClass());
90 Object[] ret = Reflection.newArray(c, argo.length);
91 System.arraycopy(argo, 0, ret, 0, argo.length);
95 public Member member(String methodName, int nonVoid, boolean complain) {
96 Class target = this.target.getClass();
97 if (methodName == null || methodName.equals("")) return null;
99 for (Method m : target.getMethods()) {
100 if (!m.getName().equals(methodName)) continue;
101 if (m.getParameterTypes().length != nonVoid) continue;
103 if (!complain) return null;
104 throw new Error("two methods with " + nonVoid + " parameters: " + target.getName() + "." + methodName);
108 if (ret != null) return ret;
111 Class c = Reflection.forNameOrNull(t.getName() + "$" + methodName);
113 for (Constructor m : c.getConstructors()) {
114 if (m.getParameterTypes().length != nonVoid) continue;
116 if (!complain) return null;
117 throw new Error("two constructors with " + nonVoid + " parameters: " + c.getName() + ".<init>()");
121 if (ret != null) return ret;
123 t = t.getSuperclass();
125 if (ret != null) return ret;
126 if (!complain) return null;
127 throw new Error("while computing return type of " +methodName+ " could not find method with name " + methodName +
128 " and " + nonVoid + " arguments");