KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gnu > kawa > reflect > SlotSet


1 package gnu.kawa.reflect;
2 import gnu.mapping.*;
3 import gnu.bytecode.*;
4 import gnu.lists.FString;
5 import gnu.expr.*;
6
7 public class SlotSet extends Procedure3 implements CanInline, Inlineable
8 {
9   /** True if this is a "static-field" operation. */
10   boolean isStatic;
11
12   /** Return value is the first argument, rather than void.
13    * Only if non-static. */

14   boolean returnSelf;
15
16   public static final SlotSet set$Mnfield$Ex = new SlotSet("set-field!", false);
17   public static final SlotSet set$Mnstatic$Mnfield$Ex
18   = new SlotSet("set-static-field!", true);
19   public static final SlotSet setFieldReturnObject
20     = new SlotSet("set-field-return-object!", false);
21   static { setFieldReturnObject.returnSelf = true; }
22
23   public SlotSet(String JavaDoc name, boolean isStatic)
24   {
25     super(name);
26     this.isStatic = isStatic;
27   }
28
29   public static void setField (Object JavaDoc obj, String JavaDoc name, Object JavaDoc value)
30   {
31     apply(false, obj, name, value);
32   }
33
34   public static void setStaticField (Object JavaDoc obj, String JavaDoc name, Object JavaDoc value)
35   {
36     apply(true, obj, name, value);
37   }
38
39   public static void apply (boolean isStatic, Object JavaDoc obj, String JavaDoc name, Object JavaDoc value)
40   {
41     Language language = Language.getDefaultLanguage();
42     boolean illegalAccess = false;
43     String JavaDoc fname = gnu.expr.Compilation.mangleNameIfNeeded(name);
44     Class JavaDoc clas = isStatic ? SlotGet.coerceToClass(obj) : obj.getClass();
45     try
46       {
47         java.lang.reflect.Field JavaDoc field = clas.getField(fname);
48     Class JavaDoc ftype = field.getType();
49         field.set(obj, language.coerceFromObject(ftype, value));
50         return;
51       }
52     catch (java.lang.NoSuchFieldException JavaDoc ex)
53       {
54       }
55     catch (IllegalAccessException JavaDoc ex)
56       {
57     illegalAccess = true;
58       }
59
60     // Try looking for a method "setFname" instead.
61
// First look for "getName" or "isName", to get the "field type".
62
try
63       {
64         java.lang.reflect.Method JavaDoc getmethod = null;
65     
66         try {
67           String JavaDoc getName = ClassExp.slotToMethodName("get", name);
68           getmethod = clas.getMethod(getName, SlotGet.noClasses);
69         } catch (Exception JavaDoc getEx) {
70           String JavaDoc getName = ClassExp.slotToMethodName("is", name);
71           getmethod = clas.getMethod(getName, SlotGet.noClasses);
72         }
73         
74     String JavaDoc setName = ClassExp.slotToMethodName("set", name);
75         Class JavaDoc[] setArgTypes = new Class JavaDoc[1];
76         setArgTypes[0] = getmethod.getReturnType();
77         java.lang.reflect.Method JavaDoc setmethod
78           = clas.getMethod(setName, setArgTypes);
79         Object JavaDoc[] args = new Object JavaDoc[1];
80         args[0] = language.coerceFromObject(setArgTypes[0], value);
81         setmethod.invoke(obj, args);
82         return;
83       }
84     catch (java.lang.reflect.InvocationTargetException JavaDoc ex)
85       {
86         throw WrappedException.wrapIfNeeded(ex.getTargetException());
87       }
88     catch (IllegalAccessException JavaDoc ex)
89       {
90         illegalAccess = true;
91       }
92     catch (java.lang.NoSuchMethodException JavaDoc ex)
93       {
94       }
95
96     if (illegalAccess)
97       throw new RuntimeException JavaDoc("illegal access for field "+name);
98     else
99       throw new RuntimeException JavaDoc ("no such field "+name
100                                   +" in "+clas.getName());
101   }
102
103   public Object JavaDoc apply3 (Object JavaDoc obj, Object JavaDoc fname, Object JavaDoc value)
104   {
105     apply(isStatic, obj, (String JavaDoc) fname, value);
106     return returnSelf ? obj : Values.empty;
107   }
108
109   public static Member
110   lookupMember (ClassType clas, String JavaDoc name, ClassType caller)
111   {
112     gnu.bytecode.Field field
113       = clas.getField(Compilation.mangleNameIfNeeded(name), -1);
114     if (field != null)
115       {
116         if (caller == null)
117           caller = Type.pointer_type;
118         if (caller.isAccessible(field.getDeclaringClass(),
119                                 field.getModifiers()))
120           return field;
121       }
122
123     String JavaDoc setName = ClassExp.slotToMethodName("set", name);
124     gnu.bytecode.Method method = clas.getMethod(setName, new Type[1]);
125     if (method == null)
126       return field;
127     else
128       return method;
129   }
130
131   static void compileSet(Procedure thisProc, ClassType ctype,
132                          Expression valArg, Object JavaDoc part, Compilation comp)
133   {
134     CodeAttr code = comp.getCode();
135     Language language = comp.getLanguage();
136     boolean isStatic
137       = thisProc instanceof SlotSet && ((SlotSet) thisProc).isStatic;
138     if (part instanceof gnu.bytecode.Field)
139       {
140         gnu.bytecode.Field field = (gnu.bytecode.Field) part;
141         boolean isStaticField = field.getStaticFlag();
142     Type ftype = language.getLangTypeFor(field.getType());
143         if (isStatic && ! isStaticField)
144           comp.error('e', ("cannot access non-static field `" + field.getName()
145                            + "' using `" + thisProc.getName() + '\''));
146         valArg.compile(comp, CheckedTarget.getInstance(ftype));
147         if (isStaticField)
148           code.emitPutStatic(field);
149         else
150           code.emitPutField(field);
151         return;
152       }
153     if (part instanceof gnu.bytecode.Method)
154       {
155         gnu.bytecode.Method method = (gnu.bytecode.Method) part;
156         boolean isStaticMethod = method.getStaticFlag();
157         if (isStatic && ! isStaticMethod)
158           comp.error('e', "cannot call non-static getter method `"
159                      + method.getName() + "' using `"
160                      + thisProc.getName() + '\'');
161         Type[] setArgTypes = method.getParameterTypes();
162         valArg.compile(comp, CheckedTarget.getInstance(language.getLangTypeFor(setArgTypes[0])));
163         if (isStaticMethod)
164           code.emitInvokeStatic(method);
165         else if (ctype.isInterface())
166           code.emitInvokeInterface(method);
167         else
168           code.emitInvokeVirtual(method);
169         return;
170       }
171   }
172
173   public Expression inline (ApplyExp exp, ExpWalker walker)
174   {
175     // Unlike, for SlotGet, we do the field-lookup at compile time
176
// rather than inline time. The main reason is that optimizing
177
// (set! CLASS-OR-OBJECT:FIELD-NAME VALUE) is tricky, since (currently)
178
// afte we've inlined setter, this method doesn't get called.
179
if (isStatic && walker.getCompilation().mustCompile)
180       return Invoke.inlineClassName (exp, 0, (InlineCalls) walker);
181     else
182       return exp;
183   }
184
185   public void compile (ApplyExp exp, Compilation comp, Target target)
186   {
187     Expression[] args = exp.getArgs();
188     int nargs = args.length;
189     if (nargs != 3)
190       {
191         String JavaDoc msg = nargs < 3 ? "too few" : "too many";
192         comp.error('e', msg + " arguments to `"+getName()+'\'');
193         comp.compileConstant(null, target);
194         return;
195       }
196     Expression arg0 = args[0];
197     Expression arg1 = args[1];
198     Expression value = args[2];
199     Type type = isStatic ? kawa.standard.Scheme.exp2Type(arg0)
200       : arg0.getType();
201     Member part = null;
202     if (type instanceof ClassType && arg1 instanceof QuoteExp)
203       {
204         Object JavaDoc val1 = ((QuoteExp) arg1).getValue();
205         ClassType ctype = (ClassType) type;
206     String JavaDoc name;
207         ClassType caller = comp.curClass != null ? comp.curClass
208           : comp.mainClass;
209         if (val1 instanceof String JavaDoc
210             || val1 instanceof FString
211             || val1 instanceof Symbol)
212       {
213             name = val1.toString();
214         part = lookupMember(ctype, name, caller);
215         if (part == null && type != Type.pointer_type)
216           comp.error('e', "no slot `"+name+"' in "+ctype.getName());
217       }
218     else if (val1 instanceof Member)
219       {
220         // Inlining (make <type> field: value) creates calls to
221
// setFieldReturnObject whose 2nd arg is a Field or Method.
222
part = (Member) val1;
223             name = part.getName();
224       }
225         else
226           name = null;
227
228     if (part != null)
229       {
230         int modifiers = part.getModifiers();
231             ClassType ptype = part.getDeclaringClass();
232         boolean isStaticField = (modifiers & Access.STATIC) != 0;
233         if (caller != null && ! caller.isAccessible(ptype, modifiers))
234           comp.error('e', "slot '"+name +"' in "+ptype.getName()
235              +" not accessible here");
236         args[0].compile(comp,
237                 isStaticField ? Target.Ignore
238                 : Target.pushValue(ctype));
239         if (returnSelf)
240           comp.getCode().emitDup(ctype);
241         compileSet(this, ctype, args[2], part, comp);
242         if (returnSelf)
243           target.compileFromStack(comp, ctype);
244         else
245           comp.compileConstant(Values.empty, target);
246         return;
247       }
248       }
249     ApplyExp.compile(exp, comp, target);
250   }
251
252   public Type getReturnType (Expression[] args)
253   {
254     if (returnSelf && args.length == 3)
255       return args[0].getType();
256     return Type.void_type;
257   }
258 }
259
Popular Tags