summaryrefslogtreecommitdiff
path: root/ipl/procs/image.icn
blob: 24f23b1be32d4119571a4cd2786b458e7ee5742f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
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