strc-syn.lua /size: 9413 b    last modification: 2021-10-28 13:50
1if not modules then modules = { } end modules ['strc-syn'] = {
2    version   = 1.001,
3    comment   = "companion to str-syn.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 next, type = next, type
10
11local context      = context
12local implement    = interfaces.implement
13
14local allocate     = utilities.storage.allocate
15
16local sorters      = sorters
17
18local structures   = structures
19local synonyms     = structures.synonyms
20local tags         = structures.tags
21
22local collected    = allocate()
23local tobesaved    = allocate()
24
25local firstofsplit = sorters.firstofsplit
26local strip        = sorters.strip
27local splitter     = sorters.splitters.utf
28
29synonyms.collected = collected
30synonyms.tobesaved = tobesaved
31
32local function initializer()
33    collected = synonyms.collected
34    tobesaved = synonyms.tobesaved
35end
36
37local function finalizer()
38    for entry, data in next, tobesaved do
39        data.hash = nil
40     -- being sparse can be an option but often we actually do want the
41     -- whole list so we don't do this ... only as possible option
42     --
43     -- local entries = data.entries
44     -- local t = { }
45     -- local n = 0
46     -- for i=1,#entries do
47     --     local e = entries[i]
48     --     if e.definition.shown then
49     --         n = n + 1
50     --         t[n] = e
51     --     end
52     -- end
53     -- data.entries = t
54    end
55end
56
57job.register('structures.synonyms.collected', tobesaved, initializer, finalizer)
58
59-- todo: allocate becomes metatable
60
61table.setmetatableindex(tobesaved,function(t,k)
62    local v = {
63        metadata = {
64            language = 'en',
65            sorted   = false,
66            class    = v
67        },
68        entries  = {
69        },
70        hash = {
71        }
72    }
73    t[k] = v
74    return v
75end)
76
77function synonyms.define(class,kind)
78    local data = tobesaved[class]
79    data.metadata.kind = kind
80end
81
82function synonyms.register(class,kind,spec)
83    local data       = tobesaved[class]
84    local hash       = data.hash
85    local definition = spec.definition
86    local tag        = definition.tag or ""
87    data.metadata.kind = kind -- runtime, not saved in format (yet)
88    if not hash[tag] then
89--         if definition.used == nil then
90--             definition.used = false
91--         end
92--         if definition.shown == nil then
93--             definition.shown = false
94--         end
95        local entries = data.entries
96        entries[#entries+1] = spec
97        hash[tag] = spec
98    end
99end
100
101function synonyms.registerused(class,tag)
102    local data = tobesaved[class]
103    local okay = data.hash[tag]
104    if okay then
105        local definition = okay.definition
106        definition.used = true
107        definition.list = true
108    end
109end
110
111function synonyms.registershown(class,tag)
112    local data = tobesaved[class]
113    local okay = data.hash[tag]
114    if okay then
115        local definition = okay.definition
116        definition.shown = true
117        definition.list  = true
118    end
119end
120
121function synonyms.isused(class,tag)
122    local data = tobesaved[class]
123    local okay = data.hash[tag]
124    return okay and okay.definition.used or false
125end
126
127function synonyms.isshown(class,tag)
128    local data = tobesaved[class]
129    local okay = data.hash[tag]
130    return okay and okay.definition.shown or false
131end
132
133function synonyms.resetused(class)
134    for tag, data in next, tobesaved[class].hash do
135--         data.definition.used = false
136        data.definition.used = nil
137    end
138end
139
140function synonyms.resetshown(class)
141    for tag, data in next, tobesaved[class].hash do
142--         data.definition.shown = false
143        data.definition.shown = nil
144    end
145end
146
147function synonyms.synonym(class,tag)
148    local data = tobesaved[class]
149    local okay = data.hash[tag]
150    if okay then
151        local definition = okay.definition
152        definition.used = true
153        definition.list = true
154        context(definition.synonym)
155    end
156end
157
158function synonyms.meaning(class,tag)
159    local data = tobesaved[class]
160    local okay = data.hash[tag]
161    if okay then
162        local definition = okay.definition
163        definition.shown = true
164        definition.list  = true
165        context(definition.meaning)
166    end
167end
168
169synonyms.compare = sorters.comparers.basic -- (a,b)
170
171function synonyms.filter(data,options)
172    local result  = { }
173    local entries = data.entries
174    local all     = options and options.criterium == interfaces.variables.all
175    if all then
176        for i=1,#entries do
177            result[i] = entries[i]
178        end
179    else
180        for i=1,#entries do
181            local entry      = entries[i]
182            local definition = entry.definition
183            if definition.list then
184                result[#result+1] = entry
185            end
186        end
187    end
188    data.result = result
189end
190
191function synonyms.prepare(data)
192    local result = data.result
193    if result then
194        for i=1, #result do
195            local entry      = result[i]
196            local definition = entry.definition
197            if definition then
198                local srt = definition.sortkey or ""
199                local tag = definition.tag or ""
200                local key = (srt ~= "" and srt) or (tag ~= "" and tag) or definition.synonym
201                if key then
202                    entry.split = splitter(strip(key))
203                end
204            end
205        end
206    end
207end
208
209function synonyms.sort(data,options)
210    sorters.sort(data.result,synonyms.compare)
211    data.metadata.sorted = true
212end
213
214function synonyms.finalize(data,options) -- mostly the same as registers so we will generalize it: sorters.split
215    local result   = data.result
216    local split    = { }
217    local nofsplit = 0
218    local lasttag  = nil
219    local lasttag  = nil
220    local nofdone  = 0
221    for k=1,#result do
222        local entry = result[k]
223        local first, tag = firstofsplit(entry)
224        if tag ~= lasttag then
225         -- if trace_registers then
226         --     report_registers("splitting at %a",tag)
227         -- end
228            done     = { }
229            nofdone  = 0
230            nofsplit = nofsplit + 1
231            lasttag  = tag
232            split[nofsplit] = { tag = tag, data = done }
233        end
234        nofdone = nofdone + 1
235        done[nofdone] = entry
236    end
237    data.result = split
238end
239
240-- for now, maybe at some point we will do a multipass or so
241-- maybe pass the settings differently
242
243local ctx_synonymentry = context.synonymentry
244
245function synonyms.flush(data,options)
246    local result = data.result
247    for i=1,#result do
248        local sublist = result[i]
249        local data    = sublist.data
250        for d=1,#data do
251            local entry = data[d].definition
252            ctx_synonymentry(d,entry.tag,entry.synonym,entry.meaning or "")
253        end
254    end
255    data.result          = nil
256    data.metadata.sorted = false
257end
258
259function synonyms.analyzed(class,options)
260    local data = collected[class]
261    if data and data.entries then
262        options = options or { }
263        sorters.setlanguage(options.language,options.method)
264        synonyms.filter(data,options)   -- filters entries to result
265        synonyms.prepare(data,options)  -- adds split table parallel to list table
266        synonyms.sort(data,options)     -- sorts entries in result
267        synonyms.finalize(data,options) -- do things with data.entries
268        data.metadata.sorted = true
269    end
270    return data and data.metadata.sorted and data.result and next(data.result)
271end
272
273function synonyms.process(class,options)
274    if synonyms.analyzed(class,options) then
275        synonyms.flush(collected[class],options)
276    end
277end
278
279-- todo: local higher up
280
281implement { name = "registerusedsynonym",  actions = synonyms.registerused,  arguments = "2 strings" }
282implement { name = "registershownsynonym", actions = synonyms.registershown, arguments = "2 strings" }
283implement { name = "synonymmeaning",       actions = synonyms.meaning,       arguments = "2 strings" }
284implement { name = "synonymname",          actions = synonyms.synonym,       arguments = "2 strings" }
285implement { name = "resetusedsynonyms",    actions = synonyms.resetused,     arguments = "string" }
286implement { name = "resetshownsynonyms",   actions = synonyms.resetshown,    arguments = "string" }
287
288implement {
289    name      = "doifelsesynonymused",
290    actions   = { synonyms.isused, commands.doifelse },
291    arguments = "2 strings",
292}
293
294implement {
295    name      = "doifelsesynonymshown",
296    actions   = { synonyms.isshown, commands.doifelse },
297    arguments = "2 strings",
298}
299
300implement {
301    name      = "registersynonym",
302    actions   = synonyms.register,
303    arguments = {
304        "string",
305        "string",
306        {
307            { "metadata", {
308                    { "catcodes", "integer" },
309                    { "coding" },
310                    { "xmlroot" }
311                }
312            },
313            {
314                "definition", {
315                    { "tag" },
316                    { "synonym" },
317                    { "meaning" },
318                    { "sortkey" },
319                    { "used", "boolean" }
320                }
321            }
322        }
323    }
324}
325
326implement {
327    name      = "processsynonyms",
328    actions   = synonyms.process,
329    arguments = {
330        "string",
331        {
332            { "criterium" },
333            { "language" },
334            { "method" }
335        }
336    }
337}
338