node-ini.lua /size: 11 Kb    last modification: 2021-10-28 13:50
1if not modules then modules = { } end modules ['node-ini'] = {
2    version   = 1.001,
3    comment   = "companion to node-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
9--[[ldx--
10<p>Most of the code that had accumulated here is now separated in modules.</p>
11--ldx]]--
12
13-- I need to clean up this module as it's a bit of a mess now. The latest luatex
14-- has most tables but we have a few more in luametatex. Also, some are different
15-- between these engines. We started out with hardcoded tables, that then ended
16-- up as comments and are now gone (as they differ per engine anyway).
17
18local next, type, tostring = next, type, tostring
19local gsub = string.gsub
20local concat, remove = table.concat, table.remove
21local sortedhash, sortedkeys, swapped = table.sortedhash, table.sortedkeys, table.swapped
22
23--[[ldx--
24<p>Access to nodes is what gives <l n='luatex'/> its power. Here we implement a
25few helper functions. These functions are rather optimized.</p>
26--ldx]]--
27
28--[[ldx--
29<p>When manipulating node lists in <l n='context'/>, we will remove nodes and
30insert new ones. While node access was implemented, we did quite some experiments
31in order to find out if manipulating nodes in <l n='lua'/> was feasible from the
32perspective of performance.</p>
33
34<p>First of all, we noticed that the bottleneck is more with excessive callbacks
35(some gets called very often) and the conversion from and to <l n='tex'/>'s
36datastructures. However, at the <l n='lua'/> end, we found that inserting and
37deleting nodes in a table could become a bottleneck.</p>
38
39<p>This resulted in two special situations in passing nodes back to <l n='tex'/>:
40a table entry with value <type>false</type> is ignored, and when instead of a
41table <type>true</type> is returned, the original table is used.</p>
42
43<p>Insertion is handled (at least in <l n='context'/> as follows. When we need to
44insert a node at a certain position, we change the node at that position by a
45dummy node, tagged <type>inline</type> which itself has_attribute the original
46node and one or more new nodes. Before we pass back the list we collapse the
47list. Of course collapsing could be built into the <l n='tex'/> engine, but this
48is a not so natural extension.</p>
49
50<p>When we collapse (something that we only do when really needed), we also
51ignore the empty nodes. [This is obsolete!]</p>
52--ldx]]--
53
54-- local gf = node.direct.getfield
55-- local n = table.setmetatableindex("number")
56-- function node.direct.getfield(a,b) n[b] = n[b] + 1  print(b,n[b]) return gf(a,b) end
57
58nodes               = nodes or { }
59local nodes         = nodes
60nodes.handlers      = nodes.handlers or { }
61
62local mark          = utilities.storage.mark
63local allocate      = utilities.storage.allocate
64local formatcolumns = utilities.formatters.formatcolumns
65
66local getsubtypes   = node.subtypes
67local getvalues     = node.values
68
69tex.magicconstants = { -- we use tex.constants for something else
70    running  = -1073741824,
71    maxdimen =  1073741823, -- 0x3FFFFFFF or 2^30-1
72    trueinch =     4736286,
73}
74
75local listcodes     = mark(getsubtypes("list"))
76local rulecodes     = mark(getsubtypes("rule"))
77local dircodes      = mark(getsubtypes("dir"))
78local glyphcodes    = mark(getsubtypes("glyph"))
79local disccodes     = mark(getsubtypes("disc"))
80local gluecodes     = mark(getsubtypes("glue"))
81local fillcodes     = mark(getsubtypes("fill"))
82local boundarycodes = mark(getsubtypes("boundary"))
83local penaltycodes  = mark(getsubtypes("penalty"))
84local kerncodes     = mark(getsubtypes("kern"))
85local margincodes   = mark(getsubtypes("marginkern"))
86local mathcodes     = mark(getsubtypes("math"))
87local noadcodes     = mark(getsubtypes("noad"))
88local radicalcodes  = mark(getsubtypes("radical"))
89local accentcodes   = mark(getsubtypes("accent"))
90local fencecodes    = mark(getsubtypes("fence"))
91----- fractioncodes = mark(getsubtypes("fraction"))
92local parcodes      = allocate { [0] = "vmode_par", "local_box", "hmode_par", "penalty", "math" }
93
94local function simplified(t)
95    local r = { }
96    for k, v in next, t do
97        r[k] = gsub(v,"_","")
98    end
99    return r
100end
101
102local nodecodes = simplified(node.types())
103local whatcodes = simplified(node.whatsits and node.whatsits() or { })
104
105local usercodes = allocate {
106    [ 97] = "attribute", -- a
107    [100] = "number",    -- d
108    [102] = "float",     -- f
109    [108] = "lua",       -- l
110    [110] = "node",      -- n
111    [115] = "string",    -- s
112    [116] = "token"      -- t
113}
114
115local noadoptions = allocate {
116    set      =        0x08,
117    unused_1 = 0x00 + 0x08,
118    unused_2 = 0x01 + 0x08,
119    axis     = 0x02 + 0x08,
120    no_axis  = 0x04 + 0x08,
121    exact    = 0x10 + 0x08,
122    left     = 0x11 + 0x08,
123    middle   = 0x12 + 0x08,
124    right    = 0x14 + 0x08,
125}
126
127local dirvalues = allocate {
128    [0] = "lefttoright",
129    [1] = "righttoleft",
130}
131
132local literalvalues = allocate {
133    [0] = "origin",
134    [1] = "page",
135    [2] = "always",
136    [3] = "raw",
137    [4] = "text",
138    [5] = "font",
139    [6] = "special",
140}
141
142local gluevalues = mark(getvalues("glue"))
143
144gluecodes        = allocate(swapped(gluecodes,gluecodes))
145dircodes         = allocate(swapped(dircodes,dircodes))
146boundarycodes    = allocate(swapped(boundarycodes,boundarycodes))
147noadcodes        = allocate(swapped(noadcodes,noadcodes))
148radicalcodes     = allocate(swapped(radicalcodes,radicalcodes))
149nodecodes        = allocate(swapped(nodecodes,nodecodes))
150whatcodes        = allocate(swapped(whatcodes,whatcodes))
151listcodes        = allocate(swapped(listcodes,listcodes))
152glyphcodes       = allocate(swapped(glyphcodes,glyphcodes))
153kerncodes        = allocate(swapped(kerncodes,kerncodes))
154penaltycodes     = allocate(swapped(penaltycodes,penaltycodes))
155mathcodes        = allocate(swapped(mathcodes,mathcodes))
156fillcodes        = allocate(swapped(fillcodes,fillcodes))
157margincodes      = allocate(swapped(margincodes,margincodes))
158disccodes        = allocate(swapped(disccodes,disccodes))
159accentcodes      = allocate(swapped(accentcodes,accentcodes))
160fencecodes       = allocate(swapped(fencecodes,fencecodes))
161parcodes         = allocate(swapped(parcodes,parcodes))
162rulecodes        = allocate(swapped(rulecodes,rulecodes))
163usercodes        = allocate(swapped(usercodes,usercodes))
164noadoptions      = allocate(swapped(noadoptions,noadoptions))
165dirvalues        = allocate(swapped(dirvalues,dirvalues))
166gluevalues       = allocate(swapped(gluevalues,gluevalues))
167literalvalues    = allocate(swapped(literalvalues,literalvalues))
168
169if not nodecodes.delimiter then
170    -- as in luametatex / lmtx
171    local d = nodecodes.delim
172    nodecodes.delimiter = d
173    nodecodes[d]        = "delimiter"
174    nodecodes.delim     = nil
175end
176
177if not nodecodes.par then
178    -- as in luametatex / lmtx
179    local p = nodecodes.localpar
180    nodecodes.par = p
181    nodecodes[p]  = "par"
182end
183
184if not nodecodes.insert then
185    -- as in luametatex / lmtx
186    local i = nodecodes.ins
187    nodecodes.insert = i
188    nodecodes[i]     = "insert"
189    nodecodes.ins    = nil
190end
191
192if not gluecodes.indentskip then
193    gluecodes.indentskip       = gluecodes.userskip
194    gluecodes.lefthangskip     = gluecodes.userskip
195    gluecodes.righthangskip    = gluecodes.userskip
196    gluecodes.correctionskip   = gluecodes.userskip
197    gluecodes.intermathskip    = gluecodes.userskip
198    gluecodes.parfillleftskip  = gluecodes.parfillskip
199    gluecodes.parfillrightskip = gluecodes.parfillskip
200end
201
202if not whatcodes.literal then
203    whatcodes.literal     = whatcodes.pdfliteral
204    whatcodes.save        = whatcodes.pdfsave
205    whatcodes.restore     = whatcodes.pdfrestore
206    whatcodes.setmatrix   = whatcodes.pdfsetmatrix
207end
208
209nodes.gluecodes            = gluecodes
210nodes.dircodes             = dircodes
211nodes.boundarycodes        = boundarycodes
212nodes.noadcodes            = noadcodes
213nodes.nodecodes            = nodecodes
214nodes.whatcodes            = whatcodes
215nodes.listcodes            = listcodes
216nodes.glyphcodes           = glyphcodes
217nodes.kerncodes            = kerncodes
218nodes.penaltycodes         = penaltycodes
219nodes.mathcodes            = mathcodes
220nodes.fillcodes            = fillcodes
221nodes.margincodes          = margincodes
222nodes.disccodes            = disccodes
223nodes.accentcodes          = accentcodes
224nodes.radicalcodes         = radicalcodes
225nodes.fencecodes           = fencecodes
226nodes.parcodes             = parcodes
227nodes.rulecodes            = rulecodes
228nodes.usercodes            = usercodes
229nodes.noadoptions          = noadoptions
230nodes.dirvalues            = dirvalues
231nodes.gluevalues           = gluevalues
232nodes.literalvalues        = literalvalues
233
234nodes.subtypes = allocate {
235    [nodecodes.accent]     = accentcodes,
236    [nodecodes.boundary]   = boundarycodes,
237    [nodecodes.dir]        = dircodes,
238    [nodecodes.disc]       = disccodes,
239    [nodecodes.fence]      = fencecodes,
240    [nodecodes.glue]       = gluecodes,
241    [nodecodes.glyph]      = glyphcodes,
242    [nodecodes.hlist]      = listcodes,
243    [nodecodes.kern]       = kerncodes,
244    [nodecodes.par]        = parcodes,
245 -- [nodecodes.marginkern] = margincodes,
246    [nodecodes.math]       = mathcodes,
247    [nodecodes.noad]       = noadcodes,
248    [nodecodes.penalty]    = penaltycodes,
249    [nodecodes.radical]    = radicalcodes,
250    [nodecodes.rule]       = rulecodes,
251 -- [nodecodes.user]       = usercodes,
252    [nodecodes.vlist]      = listcodes,
253    [nodecodes.whatsit]    = whatcodes,
254    [nodecodes.marginkern] = margincodes
255}
256
257table.setmetatableindex(nodes.subtypes,function(t,k)
258    local v = { }
259    t[k] = v
260    return v
261end)
262
263-- a few more friendly aliases:
264
265nodes.skipcodes            = gluecodes
266nodes.directioncodes       = dircodes
267nodes.whatsitcodes         = whatcodes
268nodes.marginkerncodes      = margincodes
269nodes.discretionarycodes   = disccodes
270nodes.directionvalues      = dirvalues
271nodes.skipvalues           = gluevalues
272nodes.literalvalues        = literalvalues
273
274glyphcodes.glyph           = glyphcodes.character
275
276listcodes.row              = listcodes.alignment
277listcodes.column           = listcodes.alignment
278
279kerncodes.kerning          = kerncodes.fontkern
280
281kerncodes.italiccorrection = kerncodes.italiccorrection or 1 -- new
282
283literalvalues.direct       = literalvalues.always
284
285nodes.codes = allocate { -- mostly for listing
286    glue        = skipcodes,
287    boundary    = boundarycodes,
288    noad        = noadcodes,
289    node        = nodecodes,
290    hlist       = listcodes,
291    vlist       = listcodes,
292    glyph       = glyphcodes,
293    kern        = kerncodes,
294    penalty     = penaltycodes,
295    math        = mathnodes,
296    fill        = fillcodes,
297    margin      = margincodes,
298    disc        = disccodes,
299    whatsit     = whatcodes,
300    accent      = accentcodes,
301    fence       = fencecodes,
302    rule        = rulecodes,
303    user        = usercodes,
304    noadoptions = noadoptions,
305}
306
307nodes.noadoptions = {
308    set      =        0x08,
309    unused_1 = 0x00 + 0x08,
310    unused_2 = 0x01 + 0x08,
311    axis     = 0x02 + 0x08,
312    no_axis  = 0x04 + 0x08,
313    exact    = 0x10 + 0x08,
314    left     = 0x11 + 0x08,
315    middle   = 0x12 + 0x08,
316    right    = 0x14 + 0x08,
317}
318
319local report_codes = logs.reporter("nodes","codes")
320
321function nodes.showcodes()
322    local t = { }
323    for name, codes in sortedhash(nodes.codes) do
324        local sorted = sortedkeys(codes)
325        for i=1,#sorted do
326            local s = sorted[i]
327            if type(s) ~= "number" then
328                t[#t+1] = { name, s, codes[s] }
329            end
330        end
331    end
332    formatcolumns(t)
333    for k=1,#t do
334        report_codes (t[k])
335    end
336end
337
338trackers.register("system.showcodes", nodes.showcodes)
339
340-- We don't need this sanitize-after-callback in ConTeXt and by disabling it we
341-- also have a way to check if LuaTeX itself does the right thing.
342
343if node.fix_node_lists then
344    node.fix_node_lists(false)
345end
346