Record.java 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. package kawa.lang;
  2. //import java.lang.reflect.Field; // Confuses Gcj. Should FIX gcj.
  3. import java.lang.reflect.Modifier;
  4. import java.util.Vector;
  5. import gnu.bytecode.*;
  6. import gnu.mapping.*;
  7. import gnu.lists.*;
  8. import gnu.expr.Compilation;
  9. import gnu.expr.Mangling;
  10. public class Record
  11. {
  12. public String getTypeName()
  13. {
  14. return getClass().getName();
  15. }
  16. public static boolean isRecord (Object obj) { return obj instanceof Record; }
  17. public int hashCode()
  18. {
  19. java.lang.reflect.Field[] fields = getClass().getFields();
  20. int hash = 12345;
  21. for (int i = 0; i < fields.length; i++)
  22. {
  23. java.lang.reflect.Field field = fields[i];
  24. Object value;
  25. try
  26. {
  27. value = field.get(this);
  28. }
  29. catch (IllegalAccessException ex)
  30. {
  31. continue;
  32. }
  33. if (value != null)
  34. hash ^= value.hashCode();
  35. }
  36. return hash;
  37. }
  38. static java.lang.reflect.Field getField (Class clas, String fname)
  39. throws NoSuchFieldException
  40. {
  41. ClassType ctype = (ClassType) Type.make(clas);
  42. for (gnu.bytecode.Field fld = ctype.getFields();
  43. fld != null; fld = fld.getNext())
  44. {
  45. if ((fld.getModifiers() & (Modifier.STATIC|Modifier.PUBLIC))
  46. != Modifier.PUBLIC)
  47. continue;
  48. if (! fld.getSourceName().equals(fname))
  49. continue;
  50. return fld.getReflectField();
  51. }
  52. throw new NoSuchFieldException();
  53. }
  54. public Object get (String fname, Object defaultValue)
  55. {
  56. Class clas = getClass();
  57. try
  58. {
  59. return getField(clas, fname).get(this);
  60. }
  61. catch (NoSuchFieldException ex)
  62. {
  63. //return defaultValue;
  64. throw new GenericError("no such field "+fname+" in "+clas.getName());
  65. }
  66. catch (IllegalAccessException ex)
  67. {
  68. throw new GenericError("illegal access for field "+fname);
  69. }
  70. }
  71. public Object put (String fname, Object value)
  72. {
  73. return set1 (this, fname, value);
  74. }
  75. public static Object set1 (Object record, String fname, Object value)
  76. {
  77. Class clas = record.getClass();
  78. try
  79. {
  80. java.lang.reflect.Field fld = getField(clas, fname);
  81. Object old = fld.get(record);
  82. fld.set(record, value);
  83. return old;
  84. }
  85. catch (NoSuchFieldException ex)
  86. {
  87. //throw new UnboundLocation(fname);
  88. throw new GenericError("no such field "+fname+" in "+clas.getName());
  89. }
  90. catch (IllegalAccessException ex)
  91. {
  92. throw new GenericError("illegal access for field "+fname);
  93. }
  94. }
  95. public boolean equals (Object obj)
  96. {
  97. if (this == obj)
  98. return true;
  99. Class thisClass = getClass();
  100. if (obj == null || obj.getClass() != thisClass)
  101. return false;
  102. ClassType ctype = (ClassType) Type.make(thisClass);
  103. for (gnu.bytecode.Field fld = ctype.getFields();
  104. fld != null; fld = fld.getNext())
  105. {
  106. if ((fld.getModifiers() & (Modifier.STATIC|Modifier.PUBLIC))
  107. != Modifier.PUBLIC)
  108. continue;
  109. Object value1, value2;
  110. try
  111. {
  112. java.lang.reflect.Field field = fld.getReflectField();
  113. value1 = field.get(this);
  114. value2 = field.get(obj);
  115. }
  116. catch (Exception ex)
  117. {
  118. throw new WrappedException(ex);
  119. }
  120. if (! (value1.equals(value2)))
  121. return false;
  122. }
  123. return true;
  124. }
  125. public String toString()
  126. {
  127. StringBuffer buf = new StringBuffer(200);
  128. buf.append("#<");
  129. buf.append(getTypeName());
  130. ClassType ctype = (ClassType) Type.make(getClass());
  131. for (gnu.bytecode.Field fld = ctype.getFields();
  132. fld != null; fld = fld.getNext())
  133. {
  134. if ((fld.getModifiers() & (Modifier.STATIC|Modifier.PUBLIC))
  135. != Modifier.PUBLIC)
  136. continue;
  137. Object value;
  138. try
  139. {
  140. java.lang.reflect.Field field = fld.getReflectField();
  141. value = field.get(this);
  142. }
  143. catch (Exception ex)
  144. {
  145. value = "#<illegal-access>";
  146. }
  147. buf.append(' ');
  148. buf.append(fld.getSourceName());
  149. buf.append(": ");
  150. buf.append(value);
  151. }
  152. buf.append(">");
  153. return buf.toString();
  154. }
  155. public void print(java.io.PrintWriter ps)
  156. {
  157. ps.print(toString());
  158. }
  159. public static ClassType makeRecordType (String name, LList fnames)
  160. {
  161. ClassType superClass = ClassType.make("kawa.lang.Record");
  162. String mangledName = Mangling.mangleClassName(name);
  163. ClassType clas = new ClassType(mangledName);
  164. clas.setClassfileVersion(Compilation.defaultClassFileVersion);
  165. clas.setSuper(superClass);
  166. clas.setModifiers(Access.PUBLIC|Access.SUPER);
  167. // Generate the (default) constructor.
  168. Method constructor = clas.addMethod ("<init>", Type.typeArray0,
  169. Type.voidType, Access.PUBLIC);
  170. Method superConstructor
  171. = superClass.addMethod ("<init>", Type.typeArray0,
  172. Type.voidType, Access.PUBLIC);
  173. gnu.bytecode.CodeAttr code = constructor.startCode();
  174. code.emitPushThis();
  175. code.emitInvokeSpecial(superConstructor);
  176. code.emitReturn();
  177. if (! name.equals(mangledName))
  178. {
  179. Method meth = clas.addMethod ("getTypeName", Type.typeArray0,
  180. Compilation.typeString, Access.PUBLIC);
  181. code = meth.startCode();
  182. code.emitPushString(name);
  183. code.emitReturn();
  184. }
  185. //StringBuffer fnamesBuf = new StringBuffer(100);
  186. gnu.bytecode.Field fld;
  187. while (fnames != LList.Empty)
  188. {
  189. Pair pair = (Pair) fnames;
  190. String fname = pair.getCar().toString();
  191. //fnamesBuf.append(fname); fnamesBuf.append('\n');
  192. fld = clas.addField(Mangling.mangleNameIfNeeded(fname),
  193. Type.pointer_type, Access.PUBLIC);
  194. fld.setSourceName(fname.intern());
  195. fnames = (LList) pair.getCdr();
  196. }
  197. /*
  198. fld = clas.addField("$FieldNames$", Compilation.typeString,
  199. Access.PUBLIC|Access.STATIC|Access.FINAL);
  200. ConstantValueAttr attr = new ConstantValueAttr(fnamesBuf.toString());
  201. attr.addToFrontOf(fld);
  202. */
  203. byte[][] arrays = new byte[1][];
  204. String[] names = new String[1];
  205. names[0] = mangledName;
  206. arrays[0] = clas.writeToArray();
  207. ArrayClassLoader loader = new ArrayClassLoader(names, arrays);
  208. try
  209. {
  210. Class reflectClass = loader.loadClass (mangledName);
  211. Type.registerTypeForClass(reflectClass, clas);
  212. return clas;
  213. }
  214. catch (ClassNotFoundException ex)
  215. {
  216. throw new InternalError (ex.toString());
  217. }
  218. }
  219. public static LList typeFieldNames (Class clas)
  220. {
  221. LList list = LList.Empty;
  222. /*
  223. try
  224. {
  225. Field fld = clas.getDeclaredField("$FieldNames$");
  226. String names = (String) fld.get(null);
  227. int nfields = 0;
  228. int limit = names.length() - 1;
  229. int ifield;
  230. while (limit > 0)
  231. {
  232. int start = names.lastIndexOf('\n', limit - 1);
  233. String fname = names.substring(start + 1, limit);
  234. list = new Pair(fname.intern(), list);
  235. limit = start;
  236. }
  237. return list;
  238. }
  239. catch (Exception ex)
  240. {
  241. }
  242. */
  243. ClassType ctype = (ClassType) Type.make(clas);
  244. gnu.bytecode.Field field = ctype.getFields();
  245. Vector vec = new Vector(100);
  246. for (; field != null; field = field.getNext())
  247. {
  248. if ((field.getModifiers() & (Modifier.STATIC|Modifier.PUBLIC))
  249. == Modifier.PUBLIC)
  250. vec.addElement(SimpleSymbol.valueOf(field.getSourceName()));
  251. }
  252. for (int i = vec.size(); --i >= 0; )
  253. {
  254. list = new Pair(vec.elementAt(i), list);
  255. }
  256. return list;
  257. }
  258. public static LList typeFieldNames (ClassType ctype)
  259. {
  260. return typeFieldNames(ctype.getReflectClass());
  261. }
  262. }