summaryrefslogtreecommitdiff
path: root/ipl/procs/image.icn
diff options
context:
space:
mode:
Diffstat (limited to 'ipl/procs/image.icn')
-rw-r--r--ipl/procs/image.icn323
1 files changed, 323 insertions, 0 deletions
diff --git a/ipl/procs/image.icn b/ipl/procs/image.icn
new file mode 100644
index 0000000..24f23b1
--- /dev/null
+++ b/ipl/procs/image.icn
@@ -0,0 +1,323 @@
+############################################################################
+#
+# File: image.icn
+#
+# Subject: Procedures to produce images of Icon values
+#
+# Authors: Michael Glass, Ralph E. Griswold, and David Yost
+#
+# Date: May 2, 2001
+#
+############################################################################
+#
+# This file is in the public domain.
+#
+############################################################################
+#
+# The procedure Image(x,style) produces a string image of the value x.
+# The value produced is a generalization of the value produced by
+# the Icon function image(x), providing detailed information about
+# structures. The value of style determines the formatting and
+# order of processing:
+#
+# 1 indented, with ] and ) at end of last item (default)
+# 2 indented, with ] and ) on new line
+# 3 puts the whole image on one line
+# 4 as 3, but with structures expanded breadth-first instead of
+# depth-first as for other styles.
+#
+############################################################################
+#
+# Tags are used to uniquely identify structures. A tag consists
+# of a letter identifying the type followed by an integer. The tag
+# letters are L for lists, R for records, S for sets, and T for
+# tables. The first time a structure is encountered, it is imaged
+# as the tag followed by a colon, followed by a representation of
+# the structure. If the same structure is encountered again, only
+# the tag is given.
+#
+# An example is
+#
+# a := ["x"]
+# push(a,a)
+# t := table()
+# push(a,t)
+# t[a] := t
+# t["x"] := []
+# t[t] := a
+# write(Image(t))
+#
+# which produces
+#
+# T1:[
+# "x"->L1:[],
+# L2:[
+# T1,
+# L2,
+# "x"]->T1,
+# T1->L2]
+#
+# On the other hand, Image(t,3) produces
+#
+# T1:["x"->L1:[],L2:[T1,L2,"x"]->T1,T1->L2]
+#
+# Note that a table is represented as a list of entry and assigned
+# values separated by ->.
+#
+############################################################################
+#
+# Problem:
+#
+# The procedure here really is a combination of an earlier version and
+# two modifications to it. It should be re-organized to combine the
+# presentation style and order of expansion.
+#
+# Bug:
+#
+# Since the table of structures used in a call to Image is local to
+# that call, but the numbers used to generate unique tags are static to
+# the procedures that generate tags, the same structure gets different
+# tags in different calls of Image.
+#
+############################################################################
+
+procedure Image(x,style,done,depth,nonewline)
+ local retval
+
+ if style === 4 then return Imageb(x) # breadth-first style
+
+ /style := 1
+ /done := table()
+ if /depth then depth := 0
+ else depth +:= 2
+ if (style ~= 3 & depth > 0 & /nonewline) then
+ retval := "\n" || repl(" ",depth)
+ else retval := ""
+ if match("record ",image(x)) then retval ||:= Rimage(x,done,depth,style)
+ else {
+ retval ||:=
+ case type(x) of {
+ "list": Limage(x,done,depth,style)
+ "table": Timage(x,done,depth,style)
+ "set": Simage(x,done,depth,style)
+ default: image(x)
+ }
+ }
+ depth -:= 2
+ return retval
+end
+
+# list image
+#
+procedure Limage(a,done,depth,style)
+ static i
+ local s, tag
+ initial i := 0
+ if \done[a] then return done[a]
+ done[a] := tag := "L" || (i +:= 1)
+ if *a = 0 then s := tag || ":[]" else {
+ s := tag || ":["
+ every s ||:= Image(!a,style,done,depth) || ","
+ s[-1] := endof("]",depth,style)
+ }
+ return s
+end
+
+# record image
+#
+procedure Rimage(x,done,depth,style)
+ static i
+ local s, tag
+ initial i := 0
+ s := image(x)
+ # might be record constructor
+ if match("record constructor ",s) then return s
+ if \done[x] then return done[x]
+ done[x] := tag := "R" || (i +:= 1)
+ s ?:= (="record " & (":" || (tab(upto('(') + 1))))
+ if *x = 0 then s := tag || s || ")" else {
+ s := tag || s
+ every s ||:= Image(!x,style,done,depth) || ","
+ s[-1] := endof(")",depth,style)
+ }
+ return s
+end
+
+# set image
+#
+procedure Simage(S,done,depth,style)
+ static i
+ local s, tag
+ initial i := 0
+ if \done[S] then return done[S]
+ done[S] := tag := "S" || (i +:= 1)
+ if *S = 0 then s := tag || ":[]" else {
+ s := tag || ":["
+ every s ||:= Image(!S,style,done,depth) || ","
+ s[-1] := endof("]",depth,style)
+ }
+ return s
+end
+
+# table image
+#
+procedure Timage(t,done,depth,style)
+ static i
+ local s, tag, a, a1
+ initial i := 0
+ if \done[t] then return done[t]
+ done[t] := tag := "T" || (i +:= 1)
+ if *t = 0 then s := tag || ":[]" else {
+ a := sort(t,3)
+ s := tag || ":["
+ while s ||:= Image(get(a),style,done,depth) || "->" ||
+ Image(get(a),style,done,depth,1) || ","
+ s[-1] := endof("]",depth,style)
+ }
+ return s
+end
+
+procedure endof (s,depth,style)
+ if style = 2 then return "\n" || repl(" ",depth) || "]"
+ else return "]"
+end
+
+############################################################################
+#
+# What follows is the breadth-first expansion style
+#
+
+procedure Imageb(x, done, tags)
+ local t
+
+ if /done then {
+ done := [set()] # done[1] actually done; done[2:0] pseudo-done
+ tags := table() # unique label for each structure
+ }
+
+ if member(!done, x) then return tags[x]
+
+ t := tagit(x, tags) # The tag for x if structure; image(x) if not
+
+ if /tags[x] then
+ return t # Wasn't a structure
+ else {
+ insert(done[1], x) # Mark x as actually done
+ return case t[1] of {
+ "R": rimageb(x, done, tags) # record
+ "L": limageb(x, done, tags) # list
+ "T": timageb(x, done, tags) # table
+ "S": simageb(x, done, tags) # set
+ }
+ }
+end
+
+
+# Create and return a tag for a structure, and save it in tags[x].
+# Otherwise, if x is not a structure, return image(x).
+#
+procedure tagit(x, tags)
+ local ximage, t, prefix
+ static serial
+ initial serial := table(0)
+
+ if \tags[x] then return tags[x]
+
+ if match("record constructor ", ximage := image(x)) then
+ return ximage # record constructor
+
+ if match("record ", t := ximage) |
+ ((t := type(x)) == ("list" | "table" | "set")) then {
+ prefix := map(t[1], "rlts", "RLTS")
+ return tags[x] := prefix || (serial[prefix] +:=1)
+ } # structure
+
+ else return ximage # anything else
+end
+
+
+# Every component sub-structure of the current structure gets tagged
+# and added to a pseudo-done set.
+#
+procedure defer_image(a, done, tags)
+ local x, t
+ t := set()
+ every x := !a do {
+ tagit(x, tags)
+ if \tags[x] then insert(t, x) # if x actually is a sub-structure
+ }
+ put(done, t)
+ return
+end
+
+
+# Create the image of every component of the current structure.
+# Sub-structures get deleted from the local pseudo-done set before
+# we actually create their image.
+#
+procedure do_image(a, done, tags)
+ local x, t
+ t := done[-1]
+ suspend (delete(t, x := !a), Imageb(x, done, tags))
+end
+
+
+# list image
+#
+procedure limageb(a, done, tags)
+ local s
+ if *a = 0 then s := tags[a] || ":[]" else {
+ defer_image(a, done, tags)
+ s := tags[a] || ":["
+ every s ||:= do_image(a, done, tags) || ","
+ s[-1] := "]"
+ pull(done)
+ }
+ return s
+end
+
+# record image
+#
+procedure rimageb(x, done, tags)
+ local s
+ s := image(x)
+ s ?:= (="record " & (":" || (tab(upto('(') + 1))))
+ if *x = 0 then s := tags[x] || s || ")" else {
+ defer_image(x, done, tags)
+ s := tags[x] || s
+ every s ||:= do_image(x, done, tags) || ","
+ s[-1] := ")"
+ pull(done)
+ }
+ return s
+end
+
+# set image
+#
+procedure simageb(S, done, tags)
+ local s
+ if *S = 0 then s := tags[S] || ":[]" else {
+ defer_image(S, done, tags)
+ s := tags[S] || ":["
+ every s ||:= do_image(S, done, tags) || ","
+ s[-1] := "]"
+ pull(done)
+ }
+ return s
+end
+
+# table image
+#
+procedure timageb(t, done, tags)
+ local s, a
+ if *t = 0 then s := tags[t] || ":[]" else {
+ a := sort(t,3)
+ defer_image(a, done, tags)
+ s := tags[t] || ":["
+ while s ||:= do_image([get(a)], done, tags) || "->" ||
+ do_image([get(a)], done, tags) || ","
+ s[-1] := "]"
+ pull(done)
+ }
+ return s
+end