KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gnu > kawa > functions > GetNamedPart


1 package gnu.kawa.functions;
2 import gnu.bytecode.*;
3 import gnu.mapping.*;
4 import gnu.kawa.reflect.*;
5 import gnu.expr.*;
6 import java.io.*;
7 import kawa.lang.Translator;
8
9 /** Procedure to get the value of a named component of an object. */
10
11 public class GetNamedPart extends Procedure2 implements HasSetter, CanInline
12 {
13   public static final GetNamedPart getNamedPart = new GetNamedPart();
14
15   /** PREFIX:<> is equivalent to the ClassType bound to PREFIX. */
16   public static final String JavaDoc CLASSTYPE_FOR = "<>";
17
18   /** Pseudo-method-name for the cast operation. */
19   public static final String JavaDoc CAST_METHOD_NAME = "@";
20
21   /** Pseudo-method-name for class-membership-test (instanceof) operation. */
22   public static final String JavaDoc INSTANCEOF_METHOD_NAME = "instance?";
23
24   public static String JavaDoc combineName (Expression part1, Expression part2)
25   {
26     String JavaDoc name1;
27     Object JavaDoc name2;
28     if (part2 instanceof QuoteExp
29         && (name2 = ((QuoteExp) part2).getValue()) instanceof String JavaDoc
30         && ((part1 instanceof ReferenceExp
31              && (name1 = ((ReferenceExp) part1).getSimpleName()) != null)
32             || (part1 instanceof GetNamedExp
33                 && (name1 = ((GetNamedExp) part1).combinedName) != null)))
34       return (name1+':'+name2).intern();
35     return null;
36   }
37
38   public static Expression makeExp (Expression clas, Expression member)
39   {
40     ReferenceExp rexp;
41     String JavaDoc combinedName = combineName(clas, member);
42     if (combinedName != null)
43       {
44         Translator tr = (Translator) Compilation.getCurrent();
45         Declaration decl = tr.lexical.lookup(combinedName, false/*FIXME*/);
46         if (! Declaration.isUnknown(decl))
47           return new ReferenceExp(decl);
48
49         Environment env = Environment.getCurrent();
50         Symbol symbol = env.defaultNamespace().lookup(combinedName);
51         Object JavaDoc property = null; // FIXME?
52
if (symbol != null && env.isBound(symbol, property))
53           return new ReferenceExp(combinedName);
54       }
55     if (clas instanceof ReferenceExp
56         && (rexp = (ReferenceExp) clas).isUnknown())
57       {
58         String JavaDoc name = rexp.getName();
59         try
60           {
61             /* #ifdef JAVA2 */
62             Class JavaDoc cl = Class.forName(name, false,
63                                      clas.getClass().getClassLoader());
64             /* #else */
65             // Class cl = Class.forName(name);
66
/* #endif */
67             clas = QuoteExp.getInstance(Type.make(cl));
68           }
69         catch (Throwable JavaDoc ex)
70           {
71           }
72       }
73     Expression[] args = { clas, member };
74     GetNamedExp exp = new GetNamedExp(args);
75     exp.combinedName = combinedName;
76     return exp;
77   }
78
79   public static Expression makeExp (Expression clas, String JavaDoc member)
80   {
81     return makeExp(clas, new QuoteExp(member));
82   }
83
84   public static Expression makeExp (Type type, String JavaDoc member)
85   {
86     return makeExp(new QuoteExp(type), new QuoteExp(member));
87   }
88
89   public Expression inline (ApplyExp exp, ExpWalker walker)
90   {
91     Expression[] args = exp.getArgs();
92     if (args.length != 2 || ! (args[1] instanceof QuoteExp)
93         || ! (exp instanceof GetNamedExp))
94       return exp;
95     Expression context = args[0];
96     Declaration decl = null;
97     if (context instanceof ReferenceExp)
98       {
99         ReferenceExp rexp = (ReferenceExp) context;
100         if ("*".equals(rexp.getName()))
101           return GetNamedInstancePart.makeExp(args[1]);
102         decl = rexp.getBinding();
103       }
104
105     String JavaDoc mname = ((QuoteExp) args[1]).getValue().toString();
106     Type type = context.getType();
107     boolean isInstanceOperator = context == QuoteExp.nullExp;
108     Compilation comp = walker.getCompilation();
109     Language language = comp.getLanguage();
110     Type typeval = language.getTypeFor(context, false);
111     ClassType caller = comp == null ? null
112       : comp.curClass != null ? comp.curClass
113       : comp.mainClass;
114     GetNamedExp nexp = (GetNamedExp) exp;
115
116     if (typeval instanceof Type)
117       {
118         if (mname.equals(CLASSTYPE_FOR))
119           return new QuoteExp(typeval);
120
121         if (typeval instanceof ObjectType)
122           {
123             if (mname.equals("new"))
124               return nexp.setProcedureKind('N');
125             if (mname.equals(INSTANCEOF_METHOD_NAME))
126               return nexp.setProcedureKind('I');
127             if (mname.equals(CAST_METHOD_NAME))
128               return nexp.setProcedureKind('C');
129           }
130       }
131     if (typeval instanceof ClassType)
132       {
133         if (mname.length() > 1 && mname.charAt(0) == '.')
134           {
135             // The following would also work:
136
// return nexp.setProcedureKind('D');
137
// However, it makes optimzing the 'setter' case harder.
138
return new QuoteExp(new NamedPart(typeval, mname, 'D'));
139           }
140         if (Invoke.checkKnownClass(typeval, comp) < 0)
141           return exp;
142         PrimProcedure[] methods
143           = ClassMethods.getMethods((ClassType) typeval,
144                                     Compilation.mangleName(mname),
145                                     '\0', caller, language);
146         if (methods != null && methods.length > 0)
147           {
148             nexp.methods = methods;
149             return nexp.setProcedureKind('S');
150           }
151         ApplyExp aexp = new ApplyExp(SlotGet.staticField, args);
152         aexp.setLine(exp);
153         return ((InlineCalls) walker).walkApplyOnly(aexp);
154                             
155       }
156     if (typeval != null)
157       {
158         
159       }
160
161     /*
162     if (type.isSubtype(Compilation.typeValues))
163       {
164         // FIXME
165       }
166     */

167
168     if (type.isSubtype(Compilation.typeClassType)
169         || type.isSubtype(Type.java_lang_Class_type))
170       // The container evaluates to a class (so we should look for a static
171
// field or method), but we don't know which class at compile-time.
172
// However, we should still optimize it somewhat, above. FIXME.
173
return exp;
174
175     if (type instanceof ObjectType)
176       {
177         ClassType ctype
178           = type instanceof ClassType ? (ClassType) type : Type.pointer_type;
179         PrimProcedure[] methods
180           = ClassMethods.getMethods(ctype, Compilation.mangleName(mname),
181                                     'V', caller, language);
182         if (methods != null && methods.length > 0)
183           {
184             nexp.methods = methods;
185             return nexp.setProcedureKind('M');
186           }
187         Member part = SlotGet.lookupMember(ctype, mname, caller);
188         if (part != null
189             || (mname.equals("length") && type instanceof ArrayType))
190           {
191             // FIXME: future kludge to avoid re-doing SlotGet.getField.
192
// args = new Expression[] { context, new QuoteExp(part) });
193
ApplyExp aexp = new ApplyExp(SlotGet.field, args);
194             aexp.setLine(exp);
195             return ((InlineCalls) walker).walkApplyOnly(aexp);
196           }
197
198         if (type.isSubtype(typeHasNamedParts))
199           {
200             Object JavaDoc val;
201             if (decl != null
202                 && (val = Declaration.followAliases(decl).getConstantValue()) != null)
203               {
204                 HasNamedParts value = (HasNamedParts) val;
205                 if (value.isConstant(mname))
206                   {
207                     val = value.get(mname);
208                     return QuoteExp.getInstance(val);
209                   }
210               }
211             return new ApplyExp(typeHasNamedParts.getDeclaredMethod("get", 1),
212                                 args).setLine(exp);
213           }
214       }
215
216     if (comp.getBooleanOption("warn-invoke-unknown-method", ! comp.immediate))
217       comp.error('w', "no known slot '"+mname+"' in "+type.getName());
218     return exp;
219   }
220
221   static final ClassType typeHasNamedParts
222   = ClassType.make("gnu.mapping.HasNamedParts");
223
224   public Object JavaDoc apply2 (Object JavaDoc container, Object JavaDoc part)
225     throws Throwable JavaDoc
226   {
227     if (container instanceof Values)
228       {
229         Object JavaDoc[] values = ((Values) container).getValues();
230         Values result = new Values();
231         for (int i = 0; i < values.length; i++)
232           {
233             Values.writeValues(apply2(values[i], part), result);
234           }
235         return result.canonicalize();
236       }
237     Symbol sym;
238     if (part instanceof Symbol)
239       sym = (Symbol) part;
240     else
241       sym = Namespace.EmptyNamespace.getSymbol(part.toString().intern());
242     return getNamedPart(container, sym);
243   }
244
245   public static Object JavaDoc getTypePart (Type type, String JavaDoc name)
246     throws Throwable JavaDoc
247   {
248     if (name.equals(CLASSTYPE_FOR))
249       return type;
250
251     if (type instanceof ObjectType)
252       {
253         if (name.equals(INSTANCEOF_METHOD_NAME))
254           return new NamedPart(type, name, 'I');
255         if (name.equals(CAST_METHOD_NAME))
256           return new NamedPart(type, name, 'C');
257         if (name.equals("new"))
258           return new NamedPart(type, name, 'N');
259         if (name.equals(".length")
260             || (name.length() > 1 && name.charAt(0) == '.'
261                 && type instanceof ClassType))
262           return new NamedPart(type, name, 'D');
263       }
264
265     if (type instanceof ClassType)
266       {
267         try
268           {
269             return gnu.kawa.reflect.SlotGet.staticField(type, name);
270           }
271         catch (Throwable JavaDoc ex)
272           {
273             // FIXME!
274
}
275         return ClassMethods.apply(ClassMethods.classMethods, type, name);
276       }
277     return getMemberPart(type, name);
278   }
279
280   public static Object JavaDoc getNamedPart (Object JavaDoc container, Symbol part)
281     throws Throwable JavaDoc
282   {
283     String JavaDoc name = part.getName();
284     if (container instanceof HasNamedParts)
285       return ((HasNamedParts) container).get(name);
286     if (container instanceof Class JavaDoc)
287       container = (ClassType) Type.make((Class JavaDoc) container);
288     if (container instanceof Type)
289       return getTypePart((Type) container, name);
290     return getMemberPart(container, part.toString());
291   }
292
293   public static Object JavaDoc getMemberPart(Object JavaDoc container, String JavaDoc name)
294     throws Throwable JavaDoc
295   {
296     try
297       {
298         return gnu.kawa.reflect.SlotGet.field(container, name);
299       }
300     catch (Throwable JavaDoc ex)
301       {
302         // FIXME!
303
}
304     MethodProc methods = ClassMethods.apply((ClassType) ClassType.make(container.getClass()),
305                                             Compilation.mangleName(name), '\0',
306                                             Language.getDefaultLanguage());
307     if (methods != null)
308       return new NamedPart(container, name, 'M', methods);
309     throw new RuntimeException JavaDoc("no part '"+name+"' in "+container);
310   }
311
312   public Procedure getSetter()
313   {
314     return SetNamedPart.setNamedPart;
315   }
316 }
317
318 class GetNamedExp extends ApplyExp
319 {
320   /*
321    * 'N' - new (make) - if methodName is "new".
322    * 'I' - instance of - if methodName is INSTANCEOF_METHOD_NAME.
323    * 'C' - cast - if methodName is CAST_METHOD_NAME.
324    * 'T' - type - if methodName is CLASSTYPE_FOR
325    * 'M' - non-static method
326    * 'S' - static method
327    * 'D' - if methodname starts with '.'
328    */

329   char kind;
330   PrimProcedure[] methods;
331
332   public String JavaDoc combinedName;
333
334   public void apply (CallContext ctx) throws Throwable JavaDoc
335   {
336     if (combinedName != null)
337       {
338         Environment env = ctx.getEnvironment();
339         Symbol sym = env.getSymbol(combinedName);
340         Object JavaDoc unb = gnu.mapping.Location.UNBOUND;
341         Object JavaDoc property = null; // FIXME?
342
Object JavaDoc value = env.get(sym, property, unb);
343         if (value != unb)
344           {
345             ctx.writeValue(value);
346             return;
347           }
348       }
349     super.apply(ctx);
350   }
351
352   public GetNamedExp(Expression[] args)
353   {
354     super(GetNamedPart.getNamedPart, args);
355   }
356
357   protected GetNamedExp setProcedureKind (char kind)
358   {
359     // Called from GetNamedPart.inline when the expression evaluates to a
360
// procedure that takes (at least) a 'this' parameter. If the
361
// expression is in turn used in function call position it is normally
362
// the first argment to ApplyToArgs, so setting the type to typeProcedure
363
// allows ApplyToArgs.inline to be optimized away, and then later
364
// the inline method in the GetNamedExp class can get called.
365
this.type = Compilation.typeProcedure;
366     this.kind = kind;
367     return this;
368   }
369
370   public Expression inline (ApplyExp exp, InlineCalls walker, Declaration decl)
371   {
372     Expression[] pargs = getArgs();
373     Expression context = pargs[0];
374     Expression[] args = exp.getArgs();
375     Expression[] xargs;
376     switch (kind)
377       {
378       case 'M':
379         decl = invokeDecl;
380         xargs = new Expression[args.length+2];
381         xargs[0] = pargs[0];
382         xargs[1] = pargs[1];
383         System.arraycopy(args, 0, xargs, 2, args.length);
384         break;
385       case 'N': // new
386
decl = makeDecl;
387         xargs = new Expression[args.length+1];
388         System.arraycopy(args, 0, xargs, 1, args.length);
389         xargs[0] = context;
390         break;
391       case 'I': // instance-of
392
decl = instanceOfDecl;
393         xargs = new Expression[args.length+1];
394         System.arraycopy(args, 1, xargs, 2, args.length-1);
395         xargs[0] = args[0];
396         xargs[1] = context;
397         break;
398       case 'C': // cast
399
decl = castDecl;
400         xargs = new Expression[args.length+1];
401         System.arraycopy(args, 1, xargs, 2, args.length-1);
402         xargs[0] = context;
403         xargs[1] = args[0];
404         break;
405       case 'S': // invoke-static
406
decl = invokeStaticDecl;
407         xargs = new Expression[args.length+2];
408         xargs[0] = context;
409         xargs[1] = pargs[1];
410         System.arraycopy(args, 0, xargs, 2, args.length);
411         break;
412       default:
413         return exp;
414       }
415     ApplyExp result = new ApplyExp(new ReferenceExp(decl), xargs);
416     result.setLine(exp);
417     return walker.walkApplyOnly(result);
418   }
419
420   public boolean side_effects ()
421   {
422     // The actual GetNamedExp that returns a method reference doesn't
423
// have side-effects - though applying tha result does.
424
if (kind == 'S' || kind == 'N' || kind == 'C' || kind == 'I')
425       return false;
426     if (kind == 'M')
427       return getArgs()[0].side_effects();
428     return true;
429   }
430
431   static final Declaration fieldDecl
432   = Declaration.getDeclarationFromStatic("gnu.kawa.reflect.SlotGet", "field");
433
434   static final Declaration staticFieldDecl
435   = Declaration.getDeclarationFromStatic("gnu.kawa.reflect.SlotGet", "staticField");
436
437   static final Declaration makeDecl
438   = Declaration.getDeclarationFromStatic("gnu.kawa.reflect.Invoke", "make");
439
440   static final Declaration invokeDecl
441   = Declaration.getDeclarationFromStatic("gnu.kawa.reflect.Invoke", "invoke");
442
443   static final Declaration invokeStaticDecl
444   = Declaration.getDeclarationFromStatic("gnu.kawa.reflect.Invoke", "invokeStatic");
445
446   static final Declaration instanceOfDecl
447   = Declaration.getDeclarationFromStatic("kawa.standard.Scheme", "instanceOf");
448
449   static final Declaration castDecl
450   = Declaration.getDeclarationFromStatic("gnu.kawa.functions.Convert", "as");
451 }
452
453 class NamedPart extends ProcedureN
454   implements HasSetter, Externalizable, CanInline
455 {
456   Object JavaDoc container;
457   Object JavaDoc member;
458   char kind;
459   MethodProc methods;
460
461   public NamedPart(Object JavaDoc container, Object JavaDoc member, char kind)
462   {
463     this.container = container;
464     this.member = member;
465     this.kind = kind;
466   }
467
468   public NamedPart (Object JavaDoc container, String JavaDoc mname, char kind,
469                     MethodProc methods)
470   {
471     this.container = container;
472     this.methods = methods;
473     this.member = mname;
474     this.kind = kind;
475   }
476
477   public int numArgs()
478   {
479     if (kind == 'I' || kind == 'C')
480       return 0x1001;
481     if (kind == 'D')
482       return 0x1000;
483     return 0xfffff000;
484   }
485
486   public Expression inline (ApplyExp exp, ExpWalker walker)
487   {
488     Expression[] args = exp.getArgs();
489     switch (kind)
490       {
491       case 'D':
492         String JavaDoc fname = member.toString().substring(1);
493         Expression[] xargs = new Expression[2];
494         xargs[1] = QuoteExp.getInstance(fname);
495         SlotGet proc;
496         if (args.length > 0)
497           {
498             xargs[0] = Convert.makeCoercion(args[0], new QuoteExp(container));
499             proc = SlotGet.field;
500           }
501         else
502           {
503             xargs[0] = QuoteExp.getInstance(container);
504             proc = SlotGet.staticField;
505           }
506         ApplyExp aexp = new ApplyExp(proc, xargs);
507         aexp.setLine(exp);
508         return ((InlineCalls) walker).walkApplyOnly(aexp);
509       }
510     return exp;
511   }
512
513   public void apply (CallContext ctx) throws Throwable JavaDoc
514   {
515     apply(ctx.getArgs(), ctx);
516   }
517
518   public void apply (Object JavaDoc[] args, CallContext ctx) throws Throwable JavaDoc
519   {
520     // Optimization, so that output from the
521
// method is sent directly to ctx.consumer, rather than reified.
522
if (kind == 'S')
523       methods.checkN(args, ctx);
524     else if (kind=='M')
525       {
526         int nargs = args.length;
527         Object JavaDoc[] xargs = new Object JavaDoc[nargs+1];
528         xargs[0] = container;
529         System.arraycopy(args, 0, xargs, 1, nargs);
530         methods.checkN(xargs, ctx);
531       }
532     else
533       ctx.writeValue(this.applyN(args));
534   }
535
536   public Object JavaDoc applyN (Object JavaDoc[] args)
537     throws Throwable JavaDoc
538   {
539     Object JavaDoc[] xargs;
540
541     switch (kind)
542       {
543       case 'I':
544         return kawa.standard.Scheme.instanceOf.apply2(args[0], container);
545       case 'C':
546         return gnu.kawa.functions.Convert.as.apply2(container, args[0]);
547       case 'N':
548         xargs = new Object JavaDoc[args.length+1];
549         xargs[0] = container;
550         System.arraycopy(args, 0, xargs, 1, args.length);
551         return Invoke.make.applyN(xargs);
552       case 'S':
553         return methods.applyN(args);
554       case 'M':
555         xargs = new Object JavaDoc[args.length+1];
556         xargs[0] = container;
557         System.arraycopy(args, 0, xargs, 1, args.length);
558         return methods.applyN(xargs);
559       case 'D':
560         String JavaDoc fname = member.toString().substring(1);
561         if (args.length == 0)
562           return SlotGet.staticField((ClassType) container, fname);
563         else
564           return SlotGet.field(((Type) container).coerceFromObject(args[0]), fname);
565       }
566     throw new Error JavaDoc("unknown part "+member+" in "+container);
567   }
568
569   public Procedure getSetter()
570   {
571     if (kind == 'D')
572       return new NamedPartSetter(this);
573     else
574       throw new RuntimeException JavaDoc("procedure '"+getName()+ "' has no setter");
575   }
576
577   public void set0 (Object JavaDoc value) throws Throwable JavaDoc
578   {
579     switch (kind)
580       {
581       case 'D':
582         String JavaDoc fname = member.toString().substring(1);
583         SlotSet.setStaticField((ClassType) container, fname, value);
584         return;
585       default:
586         throw new Error JavaDoc("invalid setter for "+this);
587       }
588   }
589
590   public void set1 (Object JavaDoc object, Object JavaDoc value) throws Throwable JavaDoc
591   {
592     switch (kind)
593       {
594       case 'D':
595         String JavaDoc fname = member.toString().substring(1);
596         object = ((Type) container).coerceFromObject(object);
597         SlotSet.setField(object, fname, value);
598         return;
599       default:
600         throw new Error JavaDoc("invalid setter for "+this);
601       }
602   }
603
604   public void writeExternal(ObjectOutput out) throws IOException
605   {
606     out.writeObject(container);
607     out.writeObject(member);
608     out.writeChar(kind);
609   }
610
611   public void readExternal(ObjectInput in)
612     throws IOException, ClassNotFoundException JavaDoc
613   {
614     kind = in.readChar();
615     container = (Procedure) in.readObject();
616     member = (Procedure) in.readObject();
617   }
618 }
619
620 class NamedPartSetter extends gnu.mapping.Setter
621   implements Externalizable, CanInline
622 {
623   public NamedPartSetter (NamedPart getter)
624   {
625     super(getter);
626   }
627
628   public int numArgs()
629   {
630     if (((NamedPart) getter).kind == 'D')
631       return 0x2001;
632     return 0xfffff000;
633   }
634
635   public Expression inline (ApplyExp exp, ExpWalker walker)
636   {
637     NamedPart get = (NamedPart) this.getter;
638     if (get.kind == 'D')
639       {
640         Expression[] xargs = new Expression[3];
641         xargs[1] = QuoteExp.getInstance(get.member.toString().substring(1));
642         xargs[2] = exp.getArgs()[0];
643         SlotSet proc;
644         if (exp.getArgCount() == 1)
645           {
646             xargs[0] = QuoteExp.getInstance(get.container);
647             proc = SlotSet.set$Mnstatic$Mnfield$Ex;
648           }
649         else if (exp.getArgCount() == 2)
650           {
651             xargs[0]
652               = Convert.makeCoercion(exp.getArgs()[0], new QuoteExp(get.container));
653             proc = SlotSet.set$Mnfield$Ex;
654           }
655         else
656           return exp;
657         ApplyExp aexp = new ApplyExp(proc, xargs);
658         aexp.setLine(exp);
659         return ((InlineCalls) walker).walkApplyOnly(aexp);
660       }
661     return exp;
662   }
663
664   public void writeExternal(ObjectOutput out) throws IOException
665   {
666     out.writeObject(getter);
667   }
668
669   public void readExternal(ObjectInput in)
670     throws IOException, ClassNotFoundException JavaDoc
671   {
672     getter = (Procedure) in.readObject();
673   }
674 }
675
Popular Tags