back-exp-imp-ref.lmt /size: 7616 b    last modification: 2021-10-28 13:50
1if not modules then modules = { } end modules ['back-exp-imp-ref'] = {
2    version   = 1.001,
3    comment   = "companion to back-exp.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
9-- quite some code deals with exporting references  --
10
11-- links:
12--
13-- url      :
14-- file     :
15-- internal : automatic location
16-- location : named reference
17
18-- references:
19--
20-- implicit : automatic reference
21-- explicit : named reference
22
23local tonumber = tonumber
24local lpegmatch = lpeg.match
25local insert = table.insert
26
27local references      = structures.references
28
29local structurestags  = structures.tags
30local specifications  = structurestags.specifications
31local locatedtag      = structurestags.locatedtag
32
33local backend         = structurestags.backend
34
35local setattribute    = backend.setattribute
36local extras          = backend.extras
37local fixes           = backend.fixes
38local referencehash   = backend.referencehash
39local destinationhash = backend.destinationhash
40
41local implement       = interfaces.implement
42
43local evaluators = { }
44local specials   = { }
45local explicits  = { }
46
47evaluators.inner = function(di,var)
48    local inner = var.inner
49    if inner then
50        setattribute(di,"location",inner,true)
51    end
52end
53
54evaluators.outer = function(di,var)
55    local file, url = references.checkedfileorurl(var.outer,var.outer)
56    if url then
57        setattribute(di,"url",url,true)
58    elseif file then
59        setattribute(di,"file",file,true)
60    end
61end
62
63evaluators["outer with inner"] = function(di,var)
64    local file = references.checkedfile(var.f)
65    if file then
66        setattribute(di,"file",file,true)
67    end
68    local inner = var.inner
69    if inner then
70        setattribute(di,"inner",inner,true)
71    end
72end
73
74evaluators.special = function(di,var)
75    local handler = specials[var.special]
76    if handler then
77        handler(di,var)
78    end
79end
80
81do
82
83    evaluators["special outer with operation"]     = evaluators.special
84    evaluators["special operation"]                = evaluators.special
85    evaluators["special operation with arguments"] = evaluators.special
86
87    function specials.url(di,var)
88        local url = references.checkedurl(var.operation)
89        if url and url ~= "" then
90            setattribute(di,"url",url,true)
91        end
92    end
93
94    function specials.file(di,var)
95        local file = references.checkedfile(var.operation)
96        if file and file ~= "" then
97            setattribute(di,"file",file,true)
98        end
99    end
100
101    function specials.fileorurl(di,var)
102        local file, url = references.checkedfileorurl(var.operation,var.operation)
103        if url and url ~= "" then
104            setattribute(di,"url",url,true)
105        elseif file and file ~= "" then
106            setattribute(di,"file",file,true)
107        end
108    end
109
110    function specials.internal(di,var)
111        local internal = references.checkedurl(var.operation)
112        if internal then
113            setattribute(di,"location",internal)
114        end
115    end
116
117    local function adddestination(di,references) -- todo: specials -> exporters and then concat
118        if references then
119            local reference = references.reference
120            if reference and reference ~= "" then
121                local prefix = references.prefix
122                if prefix and prefix ~= "" then
123                    setattribute(di,"prefix",prefix,true)
124                end
125                setattribute(di,"destination",reference,true)
126                for i=1,#references do
127                    local r = references[i]
128                    local e = evaluators[r.kind]
129                    if e then
130                        e(di,r)
131                    end
132                end
133            end
134        end
135    end
136
137    function extras.addimplicit(di,references)
138        if references then
139            local internal = references.internal
140            if internal then
141                setattribute(di,"implicit",internal)
142            end
143        end
144    end
145
146    function extras.addinternal(di,references)
147        if references then
148            local internal = references.internal
149            if internal then
150                setattribute(di,"internal",internal)
151            end
152        end
153    end
154
155    local p_firstpart = lpeg.Cs((1-lpeg.P(","))^0)
156
157    local function addreference(di,references)
158        if references then
159            local reference = references.reference
160            if reference and reference ~= "" then
161                local prefix = references.prefix
162                if prefix and prefix ~= "" then
163                    setattribute(di,"prefix",prefix)
164                end
165                setattribute(di,"reference",reference,true)
166                setattribute(di,"explicit",lpegmatch(p_firstpart,reference),true)
167            end
168            local internal = references.internal
169            if internal and internal ~= "" then
170                setattribute(di,"implicit",internal)
171            end
172        end
173    end
174
175    local function link(di,element,n,fulltag)
176        -- for instance in lists a link has nested elements and no own text
177        local reference = referencehash[fulltag]
178        if reference then
179            adddestination(di,structures.references.get(reference))
180            return true
181        else
182            local data = di.data
183            if data then
184                for i=1,#data do
185                    local di = data[i]
186                    if di then
187                        local fulltag = di.fulltag
188                        if fulltag and link(di,element,n,fulltag) then
189                            return true
190                        end
191                    end
192                end
193            end
194        end
195    end
196
197    local function reference(di,element,n,fulltag)
198        local destination = destinationhash[fulltag]
199        if destination then
200            local d = structures.references.internals[destination]
201            if d then
202                addreference(di,d.references)
203                return true
204            else
205                return false
206            end
207        else
208            local data = di.data
209            if data then
210                for i=1,#data do
211                    local di = data[i]
212                    if di then
213                        local fulltag = di.fulltag
214                        if fulltag and reference(di,element,n,fulltag) then
215                            return true
216                        end
217                    end
218                end
219            end
220        end
221    end
222
223    extras.adddestination = adddestination
224    extras.addreference   = addreference
225
226    extras.link           = link
227    extras.reference      = reference
228
229end
230
231do
232
233    function fixes.linenumber(di,data,i)
234        local ni = data[i+1]
235        if ni then
236            if ni.data then
237                while true do
238                    local d = ni.data[1]
239                    if d then
240                        local e = d.element
241                        if e then
242                            if e == "line" or e == "verbatimline" then
243                                insert(d.data,1,di)
244                                data[i] = false
245                                return
246                            else
247                                ni = d
248                            end
249                        else
250                            return
251                        end
252                    else
253                        return
254                    end
255                end
256            end
257        end
258    end
259
260end
261
262