location.java 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. package kawa.standard;
  2. import kawa.lang.*;
  3. import gnu.lists.*;
  4. import gnu.mapping.*;
  5. import gnu.mapping.Location; // As opposed to gnu.bytecode.Location.
  6. import gnu.expr.*;
  7. import gnu.bytecode.*;
  8. import gnu.kawa.functions.GetNamedPart;
  9. import gnu.kawa.lispexpr.LispLanguage;
  10. import gnu.kawa.reflect.Invoke;
  11. import gnu.kawa.reflect.SlotGet;
  12. import gnu.kawa.reflect.StaticFieldLocation;
  13. /**
  14. * The Syntax transformer that re-writes the Kawa "location" primitive.
  15. * @author Per Bothner
  16. */
  17. public class location extends Syntax
  18. {
  19. public static final location location = new location();
  20. static { location.setName("location"); }
  21. public Expression rewrite (Object obj, Translator tr)
  22. {
  23. if (! (obj instanceof Pair))
  24. return tr.syntaxError ("missing argument to location");
  25. Pair pair = (Pair) obj;
  26. if (pair.getCdr() != LList.Empty)
  27. return tr.syntaxError ("extra arguments to location");
  28. Expression[] args = { location.rewrite(tr.rewrite(pair.getCar()), tr) };
  29. return Invoke.makeInvokeStatic(thisType, "makeLocationProc", args);
  30. }
  31. private static ClassType thisType = ClassType.make("kawa.standard.location");
  32. public static Expression rewrite (Expression arg, Translator tr)
  33. {
  34. if (arg instanceof ReferenceExp)
  35. {
  36. ReferenceExp rexp = (ReferenceExp) arg;
  37. rexp.setDontDereference(true);
  38. Declaration decl = rexp.getBinding();
  39. if (decl != null)
  40. {
  41. decl.maybeIndirectBinding(tr);
  42. decl = Declaration.followAliases(decl);
  43. decl.setCanRead(true);
  44. decl.setCanWrite(true);
  45. }
  46. return rexp;
  47. }
  48. if (arg instanceof ApplyExp)
  49. {
  50. ApplyExp aexp = (ApplyExp) arg;
  51. Expression afunc = aexp.getFunction();
  52. Expression[] aargs = aexp.getArgs();
  53. int aalen = aargs.length;
  54. Object aproc = afunc.valueIfConstant();
  55. StaticFieldLocation sloc = null;
  56. if (aproc == GetNamedPart.getNamedPart && aalen == 2) {
  57. Expression exp = rewriteApply(aargs[0], aargs[1], tr);
  58. if (exp != null)
  59. return exp;
  60. }
  61. if (aproc == Scheme.applyToArgs && aalen == 3
  62. && aargs[0].valueIfConstant() == SlotGet.staticField) {
  63. Expression exp = rewriteApply(aargs[1], aargs[2], tr);
  64. if (exp != null)
  65. return exp;
  66. }
  67. Expression[] args = new Expression[aalen + 1];
  68. args[0] = afunc;
  69. System.arraycopy(aargs, 0, args, 1, aalen);
  70. return new ApplyExp(getMakeProcLocProc(), args);
  71. }
  72. return tr.syntaxError("invalid argument to location");
  73. }
  74. /** Helper for handling special cases to take locations of ApplyExp.
  75. * Specifically for static fields and static member classes.
  76. */
  77. static Expression rewriteApply(Expression classExp, Expression nameExp,
  78. Compilation comp) {
  79. ClassType caller = comp.curClass;
  80. Object cls = classExp.valueIfConstant();
  81. if (cls instanceof Class)
  82. cls = Type.make((Class) cls);
  83. Object nam = nameExp.valueIfConstant();
  84. if (cls instanceof ClassType && nam instanceof SimpleSymbol) {
  85. String name = nam.toString();
  86. ClassType ctype = (ClassType) cls;
  87. Member member = SlotGet.lookupMember(ctype, name, caller);
  88. if (member != null && member.getStaticFlag()) {
  89. if (member instanceof Field) {
  90. StaticFieldLocation sloc =
  91. new StaticFieldLocation(ctype, Mangling.mangleNameIfNeeded(name));
  92. ReferenceExp rexp = new ReferenceExp(sloc.getDeclaration());
  93. rexp.setDontDereference(true);
  94. return rexp;
  95. }
  96. else if (member instanceof ClassType) {
  97. ClassType cltype = (ClassType) member;
  98. if (cltype.isExisting()) {
  99. try {
  100. Class clas = cltype.getReflectClass();
  101. if (clas != null)
  102. return new QuoteExp(clas);
  103. } catch (Exception ex) {
  104. // silenty ignored
  105. }
  106. }
  107. }
  108. }
  109. }
  110. return null;
  111. }
  112. private static PrimProcedure makeProcLocProc;
  113. public static synchronized PrimProcedure getMakeProcLocProc() {
  114. if (makeProcLocProc == null) {
  115. makeProcLocProc = new PrimProcedure(ClassType.make("kawa.standard.location").getDeclaredMethod("makeProcLocation$V", 2));
  116. }
  117. return makeProcLocProc;
  118. }
  119. public static Location
  120. makeProcLocation$V (Procedure proc, Object[] args)
  121. {
  122. int nargs = args.length;
  123. if (proc instanceof gnu.kawa.functions.ApplyToArgs
  124. && nargs > 0
  125. && args[0] instanceof Procedure) // FIXME
  126. {
  127. proc = (Procedure) args[0];
  128. if (proc instanceof LocationProc && nargs == 1)
  129. return ((LocationProc) proc).getLocation();
  130. Object[] rargs = new Object[nargs-1];
  131. System.arraycopy(args, 1, rargs, 0, rargs.length);
  132. return new ProcLocation(proc, rargs);
  133. }
  134. if (proc instanceof LocationProc && nargs == 0)
  135. return ((LocationProc) proc).getLocation();
  136. return new ProcLocation(proc, args);
  137. }
  138. public static LocationProc
  139. makeLocationProc (Location loc)
  140. {
  141. return new LocationProc(loc);
  142. }
  143. }