# method dump_anything(nam1, nam2, it, filename, lineno, traversed) # or in life.icn (main) # procedure dump_anything(nam1, nam2, it, filename, lineno, traversed) # this file included after header # In one procedure file - say where "main" is # You need # "procedure dump_anything(nam1, nam2, it, filename, lineno, traversed)" # followed by # "$include "defs2.icn"" # in any class you need # "method dump_anything(nam1, nam2, it, filename, lineno, traversed)" # followed by # "$include "defs2.icn"" # I expect in a record, you could have a field "dump_anything" with the value of the above procedure. # I have not tried that. # In the initial call, nam1 and nam2 are the same - the name of the variable to dump. # nam1, recursively, becomes the name with sub-objects given with subscripts. # nam2, recursively, becomes the name with sub-objects given with sub-fields. # it is the variable to be dumped. # filename is &file in the initial call # lineno is &line in the initial call # traversed is [] in the initial call - it is used to avoid infinite recursion. # I developed it specifically for a project I am starting. # Also to practice using Unicon. # But I think it is perfectly general for debugging purposes. local ti, ti2, i, i2, field, thing chk_stlimit(&file, &line) writes("File: ", filename, " Line: ", lineno, " ") writes(&errout, "File: ", filename, " Line: ", lineno, " ") ti := type(it) # ti ? (t2 := tab(find("__"))) if (member(traversed, it) & ti ~== "cset" & ti ~== "file" & ti ~== "integer" & ti ~== "null" & ti ~== "real" & ti ~== "procedure" & ti ~== "string" & ti ~== "window") then { write(nam1, " ", image(it), " already traversed") write(&errout, nam1, " ", image(it), " already traversed") return } if (ti ~== "cset" & ti ~== "file" & ti ~== "integer" & ti ~== "null" & ti ~== "real" & ti ~== "procedure" & ti ~== "string" & ti ~== "window") then { insert(traversed, it) } case ti of { "cset": { write(ti ," name = ", nam1, " = ", it) } "file": { write(ti, " name = ", nam1, " = ", image(it)) } "integer": { write(ti, " name = ", nam1, " = ", it) } "null": { write(ti, " name = ", image(nam1), " = ", image(it)) } "real": { write(ti, " name = ", nam1, " = ", it) } "string": { write(ti, " name = ", nam1, " = ", it) } "list" : { write(ti, " name = ", nam1, " = ", image(it)) every i := 1 to *it do { dump_anything(nam1 || "[" || i || "]", nam2 || "[" || i || "]", it[i] , filename, lineno, traversed) chk_stlimit(filename, lineno) } } "set": { write(ti ," name = ", nam1, " = ", image(it)) every ( thing := ( ! it)) do { dump_anything(nam1, nam2, thing, filename, lineno, traversed) chk_stlimit(filename, lineno) } } "procedure": { write(ti, " name = ", name(it), " = ", image(it)) } "table": { write(ti ," name = ", nam1, " = ", image(it)) every ( field := key(it)) do { write(nam, "[", string(field), "] = ", image(it[string(field)])) dump_anything(nam1 || "[" || string(field) || "]", nam2 || "[" || string(field) || "]" , it[string(field)] , filename, lineno, traversed) chk_stlimit(filename, lineno) } } "window": { write("name = ", nam, " type = ", ti, " = ", image(it)) } default: { chk_stlimit(filename, lineno) # I believe I had trouble with unwanted backtracking # when I only used ever - with no count. # Not sure other "every" uses are OK in this regard. i := 1 i2 := *it every ( field := fieldnames(it)) do { write("File: ", filename," Line: ", lineno,"\n", nam1 || "[" || string(i) || "] i.e.\n" || nam2 || "." || string(field) || " = ", image(it[i])) write(&errout, "File: ", filename," Line: ", lineno,"\n", nam1 || "[" || string(i) || "] i.e.\n" || nam2 || "." || string(field) || " = ", image(it[i])) it.dump_anything(nam1 || "[" || string(i) || "]", nam2 || "." || string(field) , it[i], filename, lineno, traversed) i +:= 1 if i > i2 then break } } } end