1if not modules then modules = { } end modules ['util-sta'] = {
2 version = 1.001,
3 comment = "companion to util-ini.mkiv",
4 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files"
7}
8
9local insert, remove, fastcopy, concat = table.insert, table.remove, table.fastcopy, table.concat
10local format = string.format
11local select, tostring = select, tostring
12
13local trace_stacker = false trackers.register("stacker.resolve", function(v) trace_stacker = v end)
14
15local stacker = stacker or { }
16
17utilities.stacker = stacker
18
19local function start(s,t,first,last)
20 if s.mode == "switch" then
21 local n = tostring(t[last])
22 if trace_stacker then
23 s.report("start: %s",n)
24 end
25 return n
26 else
27 local r = { }
28 for i=first,last do
29 r[#r+1] = tostring(t[i])
30 end
31 local n = concat(r," ")
32 if trace_stacker then
33 s.report("start: %s",n)
34 end
35 return n
36 end
37end
38
39local function stop(s,t,first,last)
40 if s.mode == "switch" then
41 local n = tostring(false)
42 if trace_stacker then
43 s.report("stop: %s",n)
44 end
45 return n
46 else
47 local r = { }
48 for i=last,first,-1 do
49 r[#r+1] = tostring(false)
50 end
51 local n = concat(r," ")
52 if trace_stacker then
53 s.report("stop: %s",n)
54 end
55 return n
56 end
57end
58
59local function change(s,t1,first1,last1,t2,first2,last2)
60 if s.mode == "switch" then
61 local n = tostring(t2[last2])
62 if trace_stacker then
63 s.report("change: %s",n)
64 end
65 return n
66 else
67 local r = { }
68 for i=last1,first1,-1 do
69 r[#r+1] = tostring(false)
70 end
71 local n = concat(r," ")
72 for i=first2,last2 do
73 r[#r+1] = tostring(t2[i])
74 end
75 if trace_stacker then
76 s.report("change: %s",n)
77 end
78 return n
79 end
80end
81
82function stacker.new(name)
83
84
85
86 local report = logs.reporter("stacker",name or nil)
87
88 local s
89
90 local stack = { }
91 local list = { }
92 local ids = { }
93 local hash = { }
94
95 local hashing = true
96
97 local function push(...)
98
99 for i=1,select("#",...) do
100 insert(stack,(select(i,...)))
101 end
102 if hashing then
103 local c = concat(stack,"|")
104 local n = hash[c]
105 if not n then
106 n = #list+1
107 hash[c] = n
108 list[n] = fastcopy(stack)
109 end
110 insert(ids,n)
111 return n
112 else
113 local n = #list+1
114 list[n] = fastcopy(stack)
115 insert(ids,n)
116 return n
117 end
118 end
119
120 local function pop()
121 remove(stack)
122 remove(ids)
123 return ids[#ids] or s.unset or -1
124 end
125
126 local function clean()
127 if #stack == 0 then
128 if trace_stacker then
129 s.report("%s list entries, %s stack entries",#list,#stack)
130 end
131 end
132 end
133
134 local tops = { }
135 local top = nil
136 local switch = nil
137
138 local function resolve_reset(mode)
139 if #tops > 0 then
140 report("resetting %s left-over states of %a",#tops,name)
141 end
142 tops = { }
143 top = nil
144 switch = nil
145 end
146
147 local function resolve_begin(mode)
148 if mode then
149 switch = mode == "switch"
150 else
151 switch = s.mode == "switch"
152 end
153 top = { switch = switch }
154 insert(tops,top)
155 end
156
157 local function resolve_step(ti)
158
159 if not top then
160
161 return
162 end
163 local result = nil
164 local noftop = #top
165 if ti > 0 then
166 local current = list[ti]
167 if current then
168 local noflist = #current
169 local nofsame = 0
170 if noflist > noftop then
171 for i=1,noflist do
172 if current[i] == top[i] then
173 nofsame = i
174 else
175 break
176 end
177 end
178 else
179 for i=1,noflist do
180 if current[i] == top[i] then
181 nofsame = i
182 else
183 break
184 end
185 end
186 end
187 local plus = nofsame + 1
188 if plus <= noftop then
189 if plus <= noflist then
190 if switch then
191 result = s.change(s,top,plus,noftop,current,nofsame,noflist)
192 else
193 result = s.change(s,top,plus,noftop,current,plus,noflist)
194 end
195 else
196 if switch then
197 result = s.change(s,top,plus,noftop,current,nofsame,noflist)
198 else
199 result = s.stop(s,top,plus,noftop)
200 end
201 end
202 elseif plus <= noflist then
203 if switch then
204 result = s.start(s,current,nofsame,noflist)
205 else
206 result = s.start(s,current,plus,noflist)
207 end
208 end
209 top = current
210 else
211 if 1 <= noftop then
212 result = s.stop(s,top,1,noftop)
213 end
214 top = { }
215 end
216 return result
217 else
218 if 1 <= noftop then
219 result = s.stop(s,top,1,noftop)
220 end
221 top = { }
222 return result
223 end
224 end
225
226 local function resolve_end()
227
228 if #tops > 0 then
229 local result = s.stop(s,top,1,#top)
230 remove(tops)
231 top = tops[#tops]
232 switch = top and top.switch
233 return result
234 end
235 end
236
237 local function resolve(t)
238 resolve_begin()
239 for i=1,#t do
240 resolve_step(t[i])
241 end
242 resolve_end()
243 end
244
245 s = {
246 name = name or "unknown",
247 unset = -1,
248 report = report,
249 start = start,
250 stop = stop,
251 change = change,
252 push = push,
253 pop = pop,
254 clean = clean,
255 resolve = resolve,
256 resolve_begin = resolve_begin,
257 resolve_step = resolve_step,
258 resolve_end = resolve_end,
259 resolve_reset = resolve_reset,
260 }
261
262 return s
263
264end
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
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360 |