001: package kawa.standard;
002:
003: import gnu.mapping.*;
004: import java.io.PrintWriter;
005: import gnu.math.IntNum;
006: import gnu.kawa.functions.ObjectFormat;
007:
008: /** A TracedProcedure is a Procedure wrapper that writes trace output. */
009:
010: public class TracedProcedure extends ProcedureN {
011: public Procedure proc;
012: boolean enabled;
013:
014: static int indentationStep = 2;
015: static Symbol curIndentSym = Symbol
016: .makeUninterned("current-indentation");
017:
018: public TracedProcedure(Procedure proc, boolean enable) {
019: this .proc = proc;
020: this .enabled = enable;
021: String name = proc.getName();
022: if (name != null)
023: setName(name);
024: }
025:
026: static void put(Object value, PrintWriter out) {
027: try {
028: if (!ObjectFormat.format(value, out, 50, true))
029: out.print("...");
030: } catch (java.io.IOException ex) {
031: out.print("<caught ");
032: out.print(ex);
033: out.print('>');
034: }
035: }
036:
037: static void indent(int i, PrintWriter out) {
038: while (--i >= 0)
039: out.print(' ');
040: }
041:
042: public Object applyN(Object[] args) throws Throwable {
043: if (enabled) {
044: Environment env = Environment.getCurrent();
045: Location curIndentLoc = env.getLocation(curIndentSym);
046: Object oldIndent = curIndentLoc.get(null);
047: int curIndent;
048: if (!(oldIndent instanceof IntNum)) {
049: curIndent = 0;
050: curIndentLoc.set(IntNum.zero());
051: } else
052: curIndent = ((IntNum) oldIndent).intValue();
053: PrintWriter out = OutPort.errDefault();
054: String name = getName();
055: if (name == null)
056: name = "??";
057:
058: // Print the call arguments (indented).
059: indent(curIndent, out);
060: out.print("call to ");
061: out.print(name);
062: int len = args.length;
063: out.print(" (");
064: for (int i = 0; i < len; i++) {
065: if (i > 0)
066: out.print(' ');
067: put(args[i], out);
068: }
069: out.println(")");
070:
071: // Now do the actual call, but with the indentation incremented.
072: CallContext context = CallContext.getInstance();
073: IntNum newIndentation = IntNum.make(curIndent
074: + indentationStep);
075: Object result;
076: Object save = curIndentLoc.setWithSave(newIndentation,
077: context);
078: try {
079: result = proc.applyN(args);
080: } catch (RuntimeException e) {
081: indent(curIndent, out);
082: out.println("procedure " + name + " throws exception "
083: + e);
084: throw e;
085: } finally {
086: curIndentLoc.setRestore(save, context);
087: }
088:
089: // Print the result (indented).
090: indent(curIndent, out);
091: out.print("return from ");
092: out.print(name);
093: out.print(" => ");
094: put(result, out);
095: out.println();
096: return result;
097: }
098: return proc.applyN(args);
099: }
100:
101: public static Procedure doTrace(Procedure proc, boolean enable) {
102: if (proc instanceof TracedProcedure) {
103: ((TracedProcedure) proc).enabled = enable;
104: return proc;
105: } else
106: return new TracedProcedure(proc, enable);
107: }
108:
109: public void print(java.io.PrintWriter ps) {
110: ps.print("#<procedure ");
111: String n = getName();
112: if (n == null)
113: ps.print("<unnamed>");
114: else
115: ps.print(n);
116: ps.print(enabled ? ", traced>" : ">");
117: }
118: }
|