update copyright date 2006->2007
[sbp.git] / src / edu / berkeley / sbp / misc / ReflectiveWalker.java
1 // Copyright 2006-2007 all rights reserved; see LICENSE file for BSD-style license
2
3 package edu.berkeley.sbp.misc;
4 import edu.berkeley.sbp.*;
5 import edu.berkeley.sbp.util.*;
6 import java.io.*;
7 import java.util.*;
8 import java.lang.reflect.*;
9
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++) {
18             char c = s.charAt(i);
19             if (i==0 && c >= '0' && c <= '9') { ret.append('_'); ret.append(c); continue; }
20             switch(c) {
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;
55             }
56         }
57         return ret.toString();
58     }
59     /*
60     public Object walk(Tree<String> tree) {
61         if (tree.head()!=null) {
62             Member m = member("$"+mangle(tree.head()), 0, false);
63             if (m!=null) {
64                 if ((m instanceof Method) && ((Method)m).getReturnType()==Void.TYPE) {
65                     Reflection.fuzzyInvoke(target, m, new Object[0]);
66                 }
67             }
68         }
69         return super.walk(tree);
70     }
71     */
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);
76     }
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);
92         return ret;
93     }
94
95     public Member member(String methodName, int nonVoid, boolean complain) {
96         Class target = this.target.getClass();
97         if (methodName == null || methodName.equals("")) return null;
98         Member ret = null;
99         for (Method m : target.getMethods()) {
100             if (!m.getName().equals(methodName)) continue;
101             if (m.getParameterTypes().length != nonVoid) continue;
102             if (ret != null) {
103                 if (!complain) return null;
104                 throw new Error("two methods with " + nonVoid + " parameters: " + target.getName() + "." + methodName);
105             }
106             ret = m;
107         }
108         if (ret != null) return ret;
109         Class t = target;
110         while(t != null) {
111             Class c = Reflection.forNameOrNull(t.getName() + "$" + methodName);
112             if (c != null) {
113                 for (Constructor m : c.getConstructors()) {
114                     if (m.getParameterTypes().length != nonVoid) continue;
115                     if (ret != null) {
116                         if (!complain) return null;
117                         throw new Error("two constructors with " + nonVoid + " parameters: " + c.getName() + ".<init>()");
118                     }
119                     ret = m;
120                 }
121                 if (ret != null) return ret;
122             }
123             t = t.getSuperclass();
124         }
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");
129     }
130 }