diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/mkiv/node-res.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/mkiv/node-res.lua | 690 |
1 files changed, 690 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/context/base/mkiv/node-res.lua b/Master/texmf-dist/tex/context/base/mkiv/node-res.lua new file mode 100644 index 00000000000..4d25314ad85 --- /dev/null +++ b/Master/texmf-dist/tex/context/base/mkiv/node-res.lua @@ -0,0 +1,690 @@ +if not modules then modules = { } end modules ['node-res'] = { + version = 1.001, + comment = "companion to node-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local gmatch, format = string.gmatch, string.format +local tonumber, round = tonumber, math.round + +--[[ldx-- +<p>The next function is not that much needed but in <l n='context'/> we use +for debugging <l n='luatex'/> node management.</p> +--ldx]]-- + +local report_nodes = logs.reporter("nodes","housekeeping") + +local nodes, node = nodes, node + +nodes.pool = nodes.pool or { } +local nodepool = nodes.pool + +local whatsitcodes = nodes.whatsitcodes +local skipcodes = nodes.skipcodes +local kerncodes = nodes.kerncodes +local rulecodes = nodes.rulecodes +local nodecodes = nodes.nodecodes +local boundarycodes = nodes.boundarycodes + +local glyph_code = nodecodes.glyph + +local allocate = utilities.storage.allocate + +local texgetcount = tex.getcount + +local reserved, nofreserved = { }, 0 + +-- user nodes + +local userids = allocate() +local lastid = 0 + +setmetatable(userids, { + __index = function(t,k) + if type(k) == "string" then + lastid = lastid + 1 + rawset(userids,lastid,k) + rawset(userids,k,lastid) + return lastid + else + rawset(userids,k,k) + return k + end + end, + __call = function(t,k) + return t[k] + end +} ) + +-- nuts overload + +local nuts = nodes.nuts +local nutpool = { } +nuts.pool = nutpool + +local tonut = nuts.tonut +local tonode = nuts.tonode + +local getbox = nuts.getbox +local getfield = nuts.getfield +local getid = nuts.getid +local getlist = nuts.getlist + +local setfield = nuts.setfield +local setchar = nuts.setchar +local setlist = nuts.setlist + +local copy_nut = nuts.copy +local new_nut = nuts.new +local free_nut = nuts.free + +local copy_node = nodes.copy +local new_node = nodes.new + +-- at some point we could have a dual set (the overhead of tonut is not much larger than +-- metatable associations at the lua/c end esp if we also take assignments into account + +-- table.setmetatableindex(nodepool,function(t,k,v) +-- -- report_nodes("defining nodepool[%s] instance",k) +-- local f = nutpool[k] +-- local v = function(...) +-- return tonode(f(...)) +-- end +-- t[k] = v +-- return v +-- end) +-- +-- -- we delay one step because that permits us a forward reference +-- -- e.g. in pdfsetmatrix + +table.setmetatableindex(nodepool,function(t,k,v) + -- report_nodes("defining nodepool[%s] instance",k) + local v = function(...) + local f = nutpool[k] + local v = function(...) + return tonode(f(...)) + end + t[k] = v + return v(...) + end + t[k] = v + return v +end) + +local function register_nut(n) + nofreserved = nofreserved + 1 + reserved[nofreserved] = n + return n +end + +local function register_node(n) + nofreserved = nofreserved + 1 + if type(n) == "number" then -- isnut(n) + reserved[nofreserved] = n + else + reserved[nofreserved] = tonut(n) + end + return n +end + +nodepool.userids = userids +nodepool.register = register_node + +nutpool.userids = userids +nutpool.register = register_node -- could be register_nut + +-- so far + +local disc = register_nut(new_nut("disc")) +local kern = register_nut(new_nut("kern",kerncodes.userkern)) +local fontkern = register_nut(new_nut("kern",kerncodes.fontkern)) +local italickern = register_nut(new_nut("kern",kerncodes.italiccorrection)) +local penalty = register_nut(new_nut("penalty")) +local glue = register_nut(new_nut("glue")) -- glue.spec = nil +local glue_spec = register_nut(new_nut("glue_spec")) +local glyph = register_nut(new_nut("glyph",0)) + +local textdir = register_nut(new_nut("dir")) + +local latelua = register_nut(new_nut("whatsit",whatsitcodes.latelua)) +local special = register_nut(new_nut("whatsit",whatsitcodes.special)) +local user_n = register_nut(new_nut("whatsit",whatsitcodes.userdefined)) setfield(user_n,"type",100) -- 44 +local user_l = register_nut(new_nut("whatsit",whatsitcodes.userdefined)) setfield(user_l,"type",110) -- 44 +local user_s = register_nut(new_nut("whatsit",whatsitcodes.userdefined)) setfield(user_s,"type",115) -- 44 +local user_t = register_nut(new_nut("whatsit",whatsitcodes.userdefined)) setfield(user_t,"type",116) -- 44 +----- user_c = register_nut(new_nut("whatsit",whatsitcodes.userdefined)) setfield(user_c,"type",108) -- 44 + +local left_margin_kern = register_nut(new_nut("margin_kern",0)) +local right_margin_kern = register_nut(new_nut("margin_kern",1)) + +local lineskip = register_nut(new_nut("glue",skipcodes.lineskip)) +local baselineskip = register_nut(new_nut("glue",skipcodes.baselineskip)) +local leftskip = register_nut(new_nut("glue",skipcodes.leftskip)) +local rightskip = register_nut(new_nut("glue",skipcodes.rightskip)) + +local temp = register_nut(new_nut("temp",0)) + +local noad = register_nut(new_nut("noad")) + +local boundary = register_nut(new_nut("boundary",boundarycodes.user)) +local wordboundary = register_nut(new_nut("boundary",boundarycodes.word)) + +-- the dir field needs to be set otherwise crash: + +local rule = register_nut(new_nut("rule")) setfield(rule, "dir","TLT") +local emptyrule = register_nut(new_nut("rule",rulecodes.empty)) setfield(rule, "dir","TLT") +local userrule = register_nut(new_nut("rule",rulecodes.user)) setfield(rule, "dir","TLT") +local hlist = register_nut(new_nut("hlist")) setfield(hlist,"dir","TLT") +local vlist = register_nut(new_nut("vlist")) setfield(vlist,"dir","TLT") + +function nutpool.zeroglue(n) + if n then + return + getfield(n,"width") == 0 and + getfield(n,"stretch") == 0 and + getfield(n,"shrink") == 0 and + getfield(n,"stretch_order") == 0 and + getfield(n,"shrink_order") == 0 + else + return false + end +end + +function nutpool.glyph(fnt,chr) + local n = copy_nut(glyph) + if fnt then setfield(n,"font",fnt) end + if chr then setchar(n,chr) end + return n +end + +function nutpool.penalty(p) + local n = copy_nut(penalty) + if p and p ~= 0 then + setfield(n,"penalty",p) + end + return n +end + +function nutpool.kern(k) + local n = copy_nut(kern) + if k and k ~= 0 then + setfield(n,"kern",k) + end + return n +end + +function nutpool.boundary(v) + local n = copy_nut(boundary) + if v and v ~= 0 then + setfield(n,"value",v) + end + return n +end + +function nutpool.wordboundary(v) + local n = copy_nut(wordboundary) + if v and v ~= 0 then + setfield(n,"value",v) + end + return n +end + +function nutpool.fontkern(k) + local n = copy_nut(fontkern) + setfield(n,"kern",k) + return n +end + +function nutpool.italickern(k) + local n = copy_nut(italickern) + if k and k ~= 0 then + setfield(n,"kern",k) + end + return n +end + +function nutpool.gluespec(width,stretch,shrink,stretch_order,shrink_order) + local s = copy_nut(glue_spec) + if width and width ~= 0 then + setfield(s,"width",width) + end + if stretch and stretch ~= 0 then + setfield(s,"stretch",stretch) + end + if shrink and shrink ~= 0 then + setfield(s,"shrink",shrink) + end + if stretch_order and stretch_order ~= 0 then + setfield(s,"stretch_order",stretch_order) + end + if shrink_order and shrink_order ~= 0 then + setfield(s,"shrink_order",shrink_order) + end + return s +end + +local function someskip(skip,width,stretch,shrink,stretch_order,shrink_order) + local n = copy_nut(skip) + if width and width ~= 0 then + setfield(n,"width",width) + end + if stretch and stretch ~= 0 then + setfield(n,"stretch",stretch) + end + if shrink and shrink ~= 0 then + setfield(n,"shrink",shrink) + end + if stretch_order and stretch_order ~= 0 then + setfield(n,"stretch_order",stretch_order) + end + if shrink_order and shrink_order ~= 0 then + setfield(n,"shrink_order",shrink_order) + end + return n +end + +function nutpool.stretch(a,b) + local n = copy_nut(glue) + if b then + setfield(n,"stretch",a) + setfield(n,"stretch_order",b) + else + setfield(n,"stretch",1) + setfield(n,"stretch_order",a or 1) + end + return n +end + +function nutpool.shrink(a,b) + local n = copy_nut(glue) + if b then + setfield(n,"shrink",a) + setfield(n,"shrink_order",b) + else + setfield(n,"shrink",1) + setfield(n,"shrink_order",a or 1) + end + return n +end + +function nutpool.glue(width,stretch,shrink,stretch_order,shrink_order) + return someskip(glue,width,stretch,shrink,stretch_order,shrink_order) +end + +function nutpool.negatedglue(glue) + local n = copy_nut(glue) + local width = getfield(n,"width") + local stretch = getfield(n,"stretch") + local shrink = getfield(n,"shrink") + if width and width ~= 0 then + setfield(n,"width", -width) + end + if stretch and stretch ~= 0 then + setfield(n,"stretch",-stretch) + end + if shrink and shrink ~= 0 then + setfield(n,"shrink", -shrink) + end + return n +end + +function nutpool.leftskip(width,stretch,shrink,stretch_order,shrink_order) + return someskip(leftskip,width,stretch,shrink,stretch_order,shrink_order) +end + +function nutpool.rightskip(width,stretch,shrink,stretch_order,shrink_order) + return someskip(rightskip,width,stretch,shrink,stretch_order,shrink_order) +end + +function nutpool.lineskip(width,stretch,shrink,stretch_order,shrink_order) + return someskip(lineskip,width,stretch,shrink,stretch_order,shrink_order) +end + +function nutpool.baselineskip(width,stretch,shrink) + return someskip(baselineskip,width,stretch,shrink) +end + +function nutpool.disc() + return copy_nut(disc) +end + +function nutpool.textdir(dir) + local t = copy_nut(textdir) + setfield(t,"dir",dir) + return t +end + +function nutpool.rule(width,height,depth,dir) -- w/h/d == nil will let them adapt + local n = copy_nut(rule) + if width then -- also 0 else adapt + setfield(n,"width",width) + end + if height then -- also 0 else adapt + setfield(n,"height",height) + end + if depth then -- also 0 else adapt + setfield(n,"depth",depth) + end + if dir then + setfield(n,"dir",dir) + end + return n +end + +function nutpool.emptyrule(width,height,depth,dir) -- w/h/d == nil will let them adapt + local n = copy_nut(emptyrule) + if width then -- also 0 else adapt + setfield(n,"width",width) + end + if height then -- also 0 else adapt + setfield(n,"height",height) + end + if depth then -- also 0 else adapt + setfield(n,"depth",depth) + end + if dir then + setfield(n,"dir",dir) + end + return n +end + +function nutpool.userrule(width,height,depth,dir) -- w/h/d == nil will let them adapt + local n = copy_nut(userrule) + if width then -- also 0 else adapt + setfield(n,"width",width) + end + if height then -- also 0 else adapt + setfield(n,"height",height) + end + if depth then -- also 0 else adapt + setfield(n,"depth",depth) + end + if dir then + setfield(n,"dir",dir) + end + return n +end + +function nutpool.latelua(code) + local n = copy_nut(latelua) + setfield(n,"string",code) + return n +end + +if context and _cldo_ then + + -- a typical case where we have more nodes than nuts + + local context = context + + local f_cldo = string.formatters["_cldo_(%i)"] + local register = context.registerfunction + + local latelua_node = register_node(new_node("whatsit",whatsitcodes.latelua)) + local latelua_nut = register_nut (new_nut ("whatsit",whatsitcodes.latelua)) + + local setfield_node = nodes.setfield + local setfield_nut = nuts .setfield + + -- function nodepool.lateluafunction(f) + -- local n = copy_node(latelua_node) + -- setfield_node(n,"string",f_cldo(register(f))) + -- return n + -- end + + -- function nutpool.lateluafunction(f) + -- local n = copy_nut(latelua_nut) + -- setfield_nut(n,"string",f_cldo(register(f))) + -- return n + -- end + + -- when function in latelua: + + function nodepool.lateluafunction(f) + local n = copy_node(latelua_node) + setfield_node(n,"string",f) + return n + end + + function nutpool.lateluafunction(f) + local n = copy_nut(latelua_nut) + setfield_nut(n,"string",f) + return n + end + + local latefunction = nodepool.lateluafunction + local flushnode = context.flushnode + + -- function context.lateluafunction(f) + -- flushnode(latefunction(f)) -- hm, quite some indirect calls + -- end + + -- when function in latelua: + + -- function context.lateluafunction(f) + -- local n = copy_node(latelua_node) + -- setfield_node(n,"string",f) + -- flushnode(n) + -- end + + -- local contextsprint = context.sprint + -- local ctxcatcodes = tex.ctxcatcodes + -- local storenode = context.storenode + + -- when 0.79 is out: + + -- function context.lateluafunction(f) + -- contextsprint(ctxcatcodes,"\\cldl",storenode(latefunction(f))," ") + -- end + + -- when function in latelua: + + function context.lateluafunction(f) + local n = copy_node(latelua_node) + setfield_node(n,"string",f) + contextsprint(ctxcatcodes,"\\cldl",storenode(n)," ") + end + +end + +function nutpool.leftmarginkern(glyph,width) + local n = copy_nut(left_margin_kern) + if not glyph then + report_nodes("invalid pointer to left margin glyph node") + elseif getid(glyph) ~= glyph_code then + report_nodes("invalid node type %a for %s margin glyph node",nodecodes[glyph],"left") + else + setfield(n,"glyph",glyph) + end + if width and width ~= 0 then + setfield(n,"width",width) + end + return n +end + +function nutpool.rightmarginkern(glyph,width) + local n = copy_nut(right_margin_kern) + if not glyph then + report_nodes("invalid pointer to right margin glyph node") + elseif getid(glyph) ~= glyph_code then + report_nodes("invalid node type %a for %s margin glyph node",nodecodes[p],"right") + else + setfield(n,"glyph",glyph) + end + if width and width ~= 0 then + setfield(n,"width",width) + end + return n +end + +function nutpool.temp() + return copy_nut(temp) +end + +function nutpool.noad() + return copy_nut(noad) +end + +function nutpool.hlist(list,width,height,depth,shift) + local n = copy_nut(hlist) + if list then + setlist(n,list) + end + if width and width ~= 0 then + setfield(n,"width",width) + end + if height and height ~= 0 then + setfield(n,"height",height) + end + if depth and depth ~= 0 then + setfield(n,"depth",depth) + end + if shift and shift ~= 0 then + setfield(n,"shift",shift) + end + return n +end + +function nutpool.vlist(list,width,height,depth,shift) + local n = copy_nut(vlist) + if list then + setlist(n,list) + end + if width and width ~= 0 then + setfield(n,"width",width) + end + if height and height ~= 0 then + setfield(n,"height",height) + end + if depth and depth ~= 0 then + setfield(n,"depth",depth) + end + if shift and shift ~= 0 then + setfield(n,"shift",shift) + end + return n +end + +-- local num = userids["my id"] +-- local str = userids[num] + +function nutpool.usernumber(id,num) + local n = copy_nut(user_n) + if num then + setfield(n,"user_id",id) + setfield(n,"value",num) + elseif id then + setfield(n,"value",id) + end + return n +end + +function nutpool.userlist(id,list) + local n = copy_nut(user_l) + if list then + setfield(n,"user_id",id) + setfield(n,"value",list) + else + setfield(n,"value",id) + end + return n +end + +function nutpool.userstring(id,str) + local n = copy_nut(user_s) + if str then + setfield(n,"user_id",id) + setfield(n,"value",str) + else + setfield(n,"value",id) + end + return n +end + +function nutpool.usertokens(id,tokens) + local n = copy_nut(user_t) + if tokens then + setfield(n,"user_id",id) + setfield(n,"value",tokens) + else + setfield(n,"value",id) + end + return n +end + +-- function nutpool.usercode(id,code) +-- local n = copy_nut(user_c) +-- if code then +-- setfield(n,"user_id",id) +-- setfield(n,"value",code) +-- else +-- setfield(n,"value",id) +-- end +-- return n +-- end + +function nutpool.special(str) + local n = copy_nut(special) + setfield(n,"data",str) + return n +end + +-- housekeeping + +local function cleanup(nofboxes) -- todo + if nodes.tracers.steppers then -- to be resolved + nodes.tracers.steppers.reset() -- todo: make a registration subsystem + end + local nl, nr = 0, nofreserved + for i=1,nofreserved do + local ri = reserved[i] + -- if not (getid(ri) == glue_spec and not getfield(ri,"is_writable")) then + free_nut(reserved[i]) + -- end + end + if nofboxes then + for i=0,nofboxes do + local l = getbox(i) + if l then +-- print(nodes.listtoutf(getlist(l))) + free_nut(l) -- also list ? + nl = nl + 1 + end + end + end + reserved = { } + nofreserved = 0 + return nr, nl, nofboxes -- can be nil +end + + +local function usage() + local t = { } + for n, tag in gmatch(status.node_mem_usage,"(%d+) ([a-z_]+)") do + t[tag] = n + end + return t +end + +nutpool .cleanup = cleanup +nodepool.cleanup = cleanup + +nutpool .usage = usage +nodepool.usage = usage + +-- end + +statistics.register("cleaned up reserved nodes", function() + return format("%s nodes, %s lists of %s", cleanup(texgetcount("c_syst_last_allocated_box"))) +end) -- \topofboxstack + +statistics.register("node memory usage", function() -- comes after cleanup ! + local usage = status.node_mem_usage + if usage ~= "" then + return usage + end +end) + +lua.registerfinalizer(cleanup, "cleanup reserved nodes") |