001: package kawa.lang;
002:
003: //import java.lang.reflect.Field; // Confuses Gcj. Should FIX gcj.
004: import java.lang.reflect.Modifier;
005: import java.util.Vector;
006: import gnu.bytecode.*;
007: import gnu.mapping.*;
008: import gnu.lists.*;
009: import gnu.expr.Compilation;
010:
011: public class Record {
012: public String getTypeName() {
013: return getClass().getName();
014: }
015:
016: public static boolean isRecord(Object obj) {
017: return obj instanceof Record;
018: }
019:
020: public int hashCode() {
021: java.lang.reflect.Field[] fields = getClass().getFields();
022: int hash = 12345;
023: for (int i = 0; i < fields.length; i++) {
024: java.lang.reflect.Field field = fields[i];
025: Object value;
026: try {
027: value = field.get(this );
028: } catch (IllegalAccessException ex) {
029: continue;
030: }
031: if (value != null)
032: hash ^= value.hashCode();
033: }
034: return hash;
035: }
036:
037: static java.lang.reflect.Field getField(Class clas, String fname)
038: throws NoSuchFieldException {
039: ClassType ctype = (ClassType) Type.make(clas);
040: for (gnu.bytecode.Field fld = ctype.getFields(); fld != null; fld = fld
041: .getNext()) {
042: if ((fld.getModifiers() & (Modifier.STATIC | Modifier.PUBLIC)) != Modifier.PUBLIC)
043: continue;
044: if (!fld.getSourceName().equals(fname))
045: continue;
046: return fld.getReflectField();
047: }
048: throw new NoSuchFieldException();
049: }
050:
051: public Object get(String fname, Object defaultValue) {
052: Class clas = getClass();
053: try {
054: return getField(clas, fname).get(this );
055: } catch (NoSuchFieldException ex) {
056: //return defaultValue;
057: throw new GenericError("no such field " + fname + " in "
058: + clas.getName());
059: } catch (IllegalAccessException ex) {
060: throw new GenericError("illegal access for field " + fname);
061: }
062: }
063:
064: public Object put(String fname, Object value) {
065: return set1(this , fname, value);
066: }
067:
068: public static Object set1(Object record, String fname, Object value) {
069: Class clas = record.getClass();
070: try {
071: java.lang.reflect.Field fld = getField(clas, fname);
072: Object old = fld.get(record);
073: fld.set(record, value);
074: return old;
075: } catch (NoSuchFieldException ex) {
076: //throw new UnboundLocation(fname);
077: throw new GenericError("no such field " + fname + " in "
078: + clas.getName());
079: } catch (IllegalAccessException ex) {
080: throw new GenericError("illegal access for field " + fname);
081: }
082: }
083:
084: public boolean equals(Object obj) {
085: if (this == obj)
086: return true;
087: Class this Class = getClass();
088: if (obj == null || obj.getClass() != this Class)
089: return false;
090: ClassType ctype = (ClassType) Type.make(this Class);
091: for (gnu.bytecode.Field fld = ctype.getFields(); fld != null; fld = fld
092: .getNext()) {
093: if ((fld.getModifiers() & (Modifier.STATIC | Modifier.PUBLIC)) != Modifier.PUBLIC)
094: continue;
095: Object value1, value2;
096: try {
097: java.lang.reflect.Field field = fld.getReflectField();
098: value1 = field.get(this );
099: value2 = field.get(obj);
100: } catch (Exception ex) {
101: throw new WrappedException(ex);
102: }
103: if (!(value1.equals(value2)))
104: return false;
105: }
106: return true;
107: }
108:
109: public String toString() {
110: StringBuffer buf = new StringBuffer(200);
111: buf.append("#<");
112: buf.append(getTypeName());
113: ClassType ctype = (ClassType) Type.make(getClass());
114: for (gnu.bytecode.Field fld = ctype.getFields(); fld != null; fld = fld
115: .getNext()) {
116: if ((fld.getModifiers() & (Modifier.STATIC | Modifier.PUBLIC)) != Modifier.PUBLIC)
117: continue;
118: Object value;
119: try {
120: java.lang.reflect.Field field = fld.getReflectField();
121: value = field.get(this );
122: } catch (Exception ex) {
123: value = "#<illegal-access>";
124: }
125: buf.append(' ');
126: buf.append(fld.getSourceName());
127: buf.append(": ");
128: buf.append(value);
129: }
130: buf.append(">");
131: return buf.toString();
132: }
133:
134: public void print(java.io.PrintWriter ps) {
135: ps.print(toString());
136: }
137:
138: public static ClassType makeRecordType(String name, LList fnames) {
139: ClassType super Class = ClassType.make("kawa.lang.Record");
140: String mangledName = Compilation.mangleNameIfNeeded(name);
141: ClassType clas = new ClassType(mangledName);
142: clas.setSuper(super Class);
143: clas.access_flags = Access.PUBLIC;
144:
145: // Generate the (default) constructor.
146: Method constructor = clas.addMethod("<init>", Type.typeArray0,
147: Type.void_type, Access.PUBLIC);
148: Method super Constructor = super Class.addMethod("<init>",
149: Type.typeArray0, Type.void_type, Access.PUBLIC);
150: gnu.bytecode.CodeAttr code = constructor.startCode();
151: code.emitPushThis();
152: code.emitInvokeSpecial(super Constructor);
153: code.emitReturn();
154: if (!name.equals(mangledName)) {
155: Method meth = clas.addMethod("getTypeName",
156: Type.typeArray0, Compilation.typeString,
157: Access.PUBLIC);
158: code = meth.startCode();
159: code.emitPushString(name);
160: code.emitReturn();
161: }
162:
163: //StringBuffer fnamesBuf = new StringBuffer(100);
164: gnu.bytecode.Field fld;
165: while (fnames != LList.Empty) {
166: Pair pair = (Pair) fnames;
167: String fname = pair.car.toString();
168: //fnamesBuf.append(fname); fnamesBuf.append('\n');
169: fld = clas.addField(Compilation.mangleNameIfNeeded(fname),
170: Type.pointer_type, Access.PUBLIC);
171: fld.setSourceName(fname.intern());
172: fnames = (LList) pair.cdr;
173: }
174: /*
175: fld = clas.addField("$FieldNames$", Compilation.typeString,
176: Access.PUBLIC|Access.STATIC|Access.FINAL);
177: ConstantValueAttr attr = new ConstantValueAttr(fnamesBuf.toString());
178: attr.addToFrontOf(fld);
179: */
180:
181: byte[][] arrays = new byte[1][];
182: String[] names = new String[1];
183: names[0] = mangledName;
184: arrays[0] = clas.writeToArray();
185: ArrayClassLoader loader = new ArrayClassLoader(names, arrays);
186: try {
187: Class reflectClass = loader.loadClass(mangledName);
188: Type.registerTypeForClass(reflectClass, clas);
189: return clas;
190: } catch (ClassNotFoundException ex) {
191: throw new InternalError(ex.toString());
192: }
193: }
194:
195: public static LList typeFieldNames(Class clas) {
196: LList list = LList.Empty;
197: /*
198: try
199: {
200: Field fld = clas.getDeclaredField("$FieldNames$");
201: String names = (String) fld.get(null);
202: int nfields = 0;
203: int limit = names.length() - 1;
204:
205: int ifield;
206: while (limit > 0)
207: {
208: int start = names.lastIndexOf('\n', limit - 1);
209: String fname = names.substring(start + 1, limit);
210: list = new Pair(fname.intern(), list);
211: limit = start;
212: }
213: return list;
214: }
215: catch (Exception ex)
216: {
217: }
218: */
219: ClassType ctype = (ClassType) Type.make(clas);
220: gnu.bytecode.Field field = ctype.getFields();
221: Vector vec = new Vector(100);
222: for (; field != null; field = field.getNext()) {
223: if ((field.getModifiers() & (Modifier.STATIC | Modifier.PUBLIC)) == Modifier.PUBLIC)
224: vec.addElement(field.getSourceName());
225: }
226: for (int i = vec.size(); --i >= 0;) {
227: list = new Pair(vec.elementAt(i), list);
228: }
229: return list;
230: }
231:
232: public static LList typeFieldNames(ClassType ctype) {
233: return typeFieldNames(ctype.getReflectClass());
234: }
235: }
|