summaryrefslogtreecommitdiff
path: root/tex/context/base/node-met.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/node-met.lua')
-rw-r--r--tex/context/base/node-met.lua669
1 files changed, 0 insertions, 669 deletions
diff --git a/tex/context/base/node-met.lua b/tex/context/base/node-met.lua
deleted file mode 100644
index d6b3df213..000000000
--- a/tex/context/base/node-met.lua
+++ /dev/null
@@ -1,669 +0,0 @@
-if not modules then modules = { } end modules ['node-nut'] = {
- 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"
-}
-
--- This is an experimental module. Don't use nuts for generic code, at least not till
--- the regular code is proven stable. No support otherwise.
-
--- luatex: todo: copylist should return h, t
--- todo: see if using insert_before and insert_after makes sense here
-
--- This file is a side effect of the \LUATEX\ speed optimization project of Luigi
--- Scarso and me. As \CONTEXT\ spends over half its time in \LUA, we though that
--- using \LUAJIT\ could improve performance. We've published some of our experiences
--- elsewhere, but to summarize: \LUAJITTEX\ benefits a lot from the faster virtual
--- machine, but when jit is turned of we loose some again. We experimented with
--- ffi (without messing up the \CONTEXT\ code too much) but there we also lost more
--- than we gained (mostly due to lack of compatible userdata support: it's all or
--- nothing). This made us decide to look into the \LUA||\TEX\ interfacing and by
--- profiling and careful looking at the (of course then still beta source code) we
--- could come up with some improvements. The first showed up in 0.75 and we've more
--- on the agenda for 0.80. Although some interfaces could be sped up significantly
--- in practice we're only talking of 5||10\% on a \CONTEXT\ run and maybe more when
--- complex and extensive node list manipulations happens (we're talking of hundreds
--- of millions cross boundary calls then for documents of hundreds pages). One of the
--- changes in the \CONTEXT\ code base is that we went from indexed access to nodes to
--- function calls (in principle faster weren't it that the accessors need to do more
--- checking which makes them slower) and from there to optimizing these calls as well
--- as providing fast variants for well defined situations. At first optimizations were
--- put in a separate \type {node.fast} table although some improvements could be
--- ported to the main node functions. Because we got the feeling that more gain was
--- possible (especially when using more complex fonts and \MKIV\ functionality) we
--- eventually abandoned this approach and dropped the \type {fast} table in favour of
--- another hack. In the process we had done lots of profiling and testing so we knew
--- where time was wasted,
---
--- As lots of testing and experimenting was part of this project, I could not have
--- done without stacks of new \CD s and \DVD s. This time Porcupine Tree, No-Man
--- and Archive were came to rescue.
-
-local type, select = type, select
-local setmetatableindex = table.setmetatableindex
-
--- First we get the metatable of a node:
-
-local metatable = nil
-
-do
- local glyph = node.new("glyph",0)
- metatable = getmetatable(glyph)
- node.free(glyph)
-end
-
--- statistics.tracefunction(node, "node", "getfield","setfield")
--- statistics.tracefunction(node.direct,"node.direct","getfield","setfield")
-
--- We start with some helpers and provide all relevant basic functions in the
--- node namespace as well.
-
-local gonuts = type(node.direct) == "table"
--- local gonuts = false
-
-nodes = nodes or { }
-local nodes = nodes
-
-nodes.gonuts = gonuts
-
-local nodecodes = nodes.codes
-local hlist_code = nodecodes.hlist
-local vlist_code = nodecodes.vlist
-
-nodes.tostring = node.tostring or tostring
-nodes.copy = node.copy
-nodes.copy_list = node.copy_list
-nodes.delete = node.delete
-nodes.dimensions = node.dimensions
-nodes.end_of_math = node.end_of_math
-nodes.flush_list = node.flush_list
-nodes.flush_node = node.flush_node
-nodes.free = node.free
-nodes.insert_after = node.insert_after
-nodes.insert_before = node.insert_before
-nodes.hpack = node.hpack
-nodes.new = node.new
-nodes.tail = node.tail
-nodes.traverse = node.traverse
-nodes.traverse_id = node.traverse_id
-nodes.slide = node.slide
-nodes.vpack = node.vpack
-nodes.fields = node.fields
-
-nodes.first_glyph = node.first_glyph
-nodes.first_character = node.first_character
-nodes.has_glyph = node.has_glyph or node.first_glyph
-
-nodes.current_attr = node.current_attr
-nodes.do_ligature_n = node.do_ligature_n
-nodes.has_field = node.has_field
-nodes.last_node = node.last_node
-nodes.usedlist = node.usedlist
-nodes.protrusion_skippable = node.protrusion_skippable
-nodes.write = node.write
-
-nodes.has_attribute = node.has_attribute
-nodes.set_attribute = node.set_attribute
-nodes.unset_attribute = node.unset_attribute
-
-nodes.protect_glyphs = node.protect_glyphs
-nodes.unprotect_glyphs = node.unprotect_glyphs
-nodes.kerning = node.kerning
-nodes.ligaturing = node.ligaturing
-nodes.mlist_to_hlist = node.mlist_to_hlist
-
-if not gonuts or not node.getfield then
- node.getfield = metatable.__index
- node.setfield = metatable.__newindex
-end
-
--- if gonuts then
- nodes.tonode = function(n) return n end
- nodes.tonut = function(n) return n end
--- end
-
-local getfield = node.getfield
-local setfield = node.setfield
-
-local getattr = getfield
-local setattr = setfield
-
-local getnext = node.getnext or function(n) return getfield(n,"next") end
-local getprev = node.getprev or function(n) return getfield(n,"prev") end
-local getid = node.getid or function(n) return getfield(n,"id") end
-local getchar = node.getchar or function(n) return getfield(n,"char") end
-local getfont = node.getfont or function(n) return getfield(n,"font") end
-local getsubtype = node.getsubtype or function(n) return getfield(n,"subtype") end
-local getlist = node.getlist or function(n) return getfield(n,"list") end
-local getleader = node.getleader or function(n) return getfield(n,"leader") end
-
-nodes.getfield = getfield
-nodes.getattr = getattr
-
-nodes.setfield = setfield
-nodes.setattr = setattr
-
-nodes.getnext = getnext
-nodes.getprev = getprev
-nodes.getid = getid
-nodes.getchar = getchar
-nodes.getfont = getfont
-nodes.getsubtype = getsubtype
-nodes.getlist = getlist
-nodes.getleader = getleader
-
-nodes.getbox = node.getbox or tex.getbox
-nodes.setbox = node.setbox or tex.setbox
-nodes.getskip = node.getskip or tex.get
-
-local n_new_node = nodes.new
-local n_free_node = nodes.free
-local n_setfield = nodes.setfield
-local n_getfield = nodes.getfield
-local n_getnext = nodes.getnext
-local n_getprev = nodes.getprev
-local n_getid = nodes.getid
-local n_getlist = nodes.getlist
-local n_copy_node = nodes.copy
-local n_copy_list = nodes.copy_list
-local n_find_tail = nodes.tail
-local n_insert_after = nodes.insert_after
-local n_insert_before = nodes.insert_before
-local n_slide = nodes.slide
-
-local n_remove_node = node.remove -- not yet nodes.remove
-
--- if t.id == glue_code then
--- local s = t.spec
--- if s and s.writable then
--- free_node(s)
--- end
--- t.spec = nil
--- end
-
-local function remove(head,current,free_too)
- local t = current
- head, current = n_remove_node(head,current)
- if t then
- if free_too then
- n_free_node(t)
- t = nil
- else
- n_setfield(t,"next",nil)
- n_setfield(t,"prev",nil)
- end
- end
- return head, current, t
-end
-
-nodes.remove = remove
-
-function nodes.delete(head,current)
- return remove(head,current,true)
-end
-
--- local h, c = nodes.replace(head,current,new)
--- local c = nodes.replace(false,current,new)
--- local c = nodes.replace(current,new)
---
--- todo: check for new.next and find tail
-
-function nodes.replace(head,current,new) -- no head returned if false
- if not new then
- head, current, new = false, head, current
--- current, new = head, current
- end
- local prev = n_getprev(current)
- local next = n_getnext(current)
- if next then
- n_setfield(new,"next",next)
- n_setfield(next,"prev",new)
- end
- if prev then
- n_setfield(new,"prev",prev)
- n_setfield(prev,"next",new)
- end
- if head then
- if head == current then
- head = new
- end
- n_free_node(current)
- return head, new
- else
- n_free_node(current)
- return new
- end
-end
-
-local function count(stack,flat)
- local n = 0
- while stack do
- local id = n_getid(stack)
- if not flat and id == hlist_code or id == vlist_code then
- local list = n_getlist(stack)
- if list then
- n = n + 1 + count(list) -- self counts too
- else
- n = n + 1
- end
- else
- n = n + 1
- end
- stack = n_getnext(stack)
- end
- return n
-end
-
-nodes.count = count
-
-function nodes.append(head,current,...)
- for i=1,select("#",...) do
- head, current = n_insert_after(head,current,(select(i,...)))
- end
- return head, current
-end
-
-function nodes.prepend(head,current,...)
- for i=1,select("#",...) do
- head, current = n_insert_before(head,current,(select(i,...)))
- end
- return head, current
-end
-
-function nodes.linked(...)
- local head, last
- for i=1,select("#",...) do
- local next = select(i,...)
- if next then
- if head then
- n_setfield(last,"next",next)
- n_setfield(next,"prev",last)
- else
- head = next
- end
- last = n_find_tail(next) -- we could skip the last one
- end
- end
- return head
-end
-
-function nodes.concat(list) -- consider tail instead of slide
- local head, tail
- for i=1,#list do
- local li = list[i]
- if li then
- if head then
- n_setfield(tail,"next",li)
- n_setfield(li,"prev",tail)
- else
- head = li
- end
- tail = n_slide(li)
- end
- end
- return head, tail
-end
-
---[[
-<p>At some point we ran into a problem that the glue specification
-of the zeropoint dimension was overwritten when adapting a glue spec
-node. This is a side effect of glue specs being shared. After a
-couple of hours tracing and debugging Taco and I came to the
-conclusion that it made no sense to complicate the spec allocator
-and settled on a writable flag. This all is a side effect of the
-fact that some glues use reserved memory slots (with the zeropoint
-glue being a noticeable one). So, next we wrap this into a function
-and hide it for the user. And yes, LuaTeX now gives a warning as
-well.</p>
-]]--
-
-function nodes.writable_spec(n) -- not pool
- local spec = n_getfield(n,"spec")
- if not spec then
- spec = n_copy_node(glue_spec)
- n_setfield(n,"spec",spec)
- elseif not n_getfield(spec,"writable") then
- spec = n_copy_node(spec)
- n_setfield(n,"spec",spec)
- end
- return spec
-end
-
-if gonuts then
-
- function nodes.reference(n)
- return n and tonut(n) or "<none>"
- end
-
-else
-
- local left, space = lpeg.P("<"), lpeg.P(" ")
-
- local reference = left * (1-left)^0 * left * space^0 * lpeg.C((1-space)^0)
-
- function nodes.reference(n)
- return n and lpegmatch(reference,tostring(n)) or "<none>"
- end
-
-end
-
--- Here starts an experiment with metatables. Of course this only works with nodes
--- wrapped in userdata with a metatable.
---
--- Nodes are kind of special in the sense that you need to keep an eye on creation
--- and destruction. This is quite natural if you consider that changing the content
--- of a node would also change any copy (or alias). As there are too many pitfalls
--- we don't have this kind of support built in \LUATEX, which means that macro
--- packages are free to provide their own. One can even use local variants.
---
--- n1 .. n2 : append nodes, no copies
--- n1 * 5 : append 4 copies of nodes
--- 5 + n1 : strip first 5 nodes
--- n1 - 5 : strip last 5 nodes
--- n1 + n2 : inject n2 after first of n1
--- n1 - n2 : inject n2 before last of n1
--- n1^2 : two copies of nodes (keep orginal)
--- - n1 : reverse nodes
--- n1/f : apply function to nodes
-
--- local s = nodes.typesetters.tonodes
---
--- local function w(lst)
--- context.dontleavehmode()
--- context(lst)
--- context.par()
--- end
---
--- local n1 = s("a")
--- local n2 = s("b")
--- local n3 = s("c")
--- local n4 = s("d")
--- local n5 = s("e")
--- local n6 = s("f")
--- local n7 = s("g")
---
--- local n0 = n1 .. (n2 * 10).. n3 .. (5 * n4) .. n5 .. ( 5 * n6 ) .. n7 / function(n) n.char = string.byte("!") return n end
---
--- w(#n0)
---
--- w(n0)
---
--- local n1 = s("a") * 10
--- local n2 = s("b") * 10
---
--- local n0 = ((5 + n1) .. (n2 - 5) )
--- local n0 = - n0
---
--- local n0 = nil .. n0^3 .. nil
---
--- w(n0)
---
--- w ( s("a") + s("b") ) w ( s("a") + 4*s("b") ) w ( 4*s("a") + s("b") ) w ( 4*s("a") + 4*s("b") )
--- w ( s("a") - s("b") ) w ( s("a") - 4*s("b") ) w ( 4*s("a") - s("b") ) w ( 4*s("a") - 4*s("b") )
-
-local n_remove_node = nodes.remove
-
-metatable.__concat = function(n1,n2) -- todo: accept nut on one end
- if not n1 then
- return n2
- elseif not n2 then
- return n1
- elseif n1 == n2 then
- -- or abort
- return n2 -- or n2 * 2
- else
- local tail = n_find_tail(n1)
- n_setfield(tail,"next",n2)
- n_setfield(n2,"prev",tail)
- return n1
- end
-end
-
-metatable.__mul = function(n,multiplier)
- if type(multiplier) ~= "number" then
- n, multiplier = multiplier, n
- end
- if multiplier <= 1 then
- return n
- elseif n_getnext(n) then
- local head
- for i=2,multiplier do
- local h = n_copy_list(n)
- if head then
- local t = n_find_tail(h)
- n_setfield(t,"next",head)
- n_setfield(head,"prev",t)
- end
- head = h
- end
- local t = n_find_tail(n)
- n_setfield(t,"next",head)
- n_setfield(head,"prev",t)
- else
- local head
- for i=2,multiplier do
- local c = n_copy_node(n)
- if head then
- n_setfield(c,"next",head)
- n_setfield(head,"prev",c)
- end
- head = c
- end
- n_setfield(n,"next",head)
- n_setfield(head,"prev",n)
- end
- return n
-end
-
-metatable.__sub = function(first,second)
- if type(second) == "number" then
- local tail = n_find_tail(first)
- for i=1,second do
- local prev = n_getfield(tail,"prev")
- n_free_node(tail) -- can become flushlist/flushnode
- if prev then
- tail = prev
- else
- return nil
- end
- end
- if tail then
- n_setfield(tail,"next",nil)
- return first
- else
- return nil
- end
- else
- -- aaaaa - bbb => aaaabbba
- local firsttail = n_find_tail(first)
- local prev = n_getprev(firsttail)
- if prev then
- local secondtail = n_find_tail(second)
- n_setfield(secondtail,"next",firsttail)
- n_setfield(firsttail,"prev",ltail)
- n_setfield(prev,"next",second)
- n_setfield(second,"prev",prev)
- return first
- else
- local secondtail = n_find_tail(second)
- n_setfield(secondtail,"next",first)
- n_setfield(first,"prev",ltail)
- return second
- end
- end
-end
-
-metatable.__add = function(first,second)
- if type(first) == "number" then
- local head = second
- for i=1,first do
- local second = n_getnext(head)
- n_free_node(head) -- can become flushlist/flushnode
- if second then
- head = second
- else
- return nil
- end
- end
- if head then
- n_setfield(head,"prev",nil)
- return head
- else
- return nil
- end
- else
- -- aaaaa + bbb => abbbaaaa
- local next = n_getnext(first)
- if next then
- local secondtail = n_find_tail(second)
- n_setfield(first,"next",second)
- n_setfield(second,"prev",first)
- n_setfield(secondtail,"next",next)
- n_setfield(next,"prev",secondtail)
- else
- n_setfield(first,"next",second)
- n_setfield(second,"prev",first)
- end
- return first
- end
-end
-
-metatable.__len = function(current)
- local length = 0
- while current do
- current = n_getnext(current)
- length = length + 1
- end
- return length
-end
-
-metatable.__div = function(list,action)
- return action(list) or list -- always a value
-end
-
-metatable.__pow = function(n,multiplier)
- local tail = n
- local head = nil
- if getnext(n) then
- if multiplier == 1 then
- head = n_copy_list(n)
- else
- for i=1,multiplier do
- local h = n_copy_list(n)
- if head then
- local t = n_find_tail(h)
- n_setfield(t,"next",head)
- n_setfield(head,"prev",t)
- end
- head = h
- end
- end
- else
- if multiplier == 1 then
- head = n_copy_node(n)
- else
- for i=2,multiplier do
- local c = n_copy_node(n)
- if head then
- n_setfield(head,"next",c)
- n_setfield(c,"prev",head)
- end
- head = c
- end
- end
- end
- -- todo: tracing
- return head
-end
-
-metatable.__unm = function(head)
- local last = head
- local first = head
- local current = n_getnext(head)
- while current do
- local next = n_getnext(current)
- n_setfield(first,"prev",current)
- n_setfield(current,"next",first)
- first = current
- current = next
- end
- n_setfield(first,"prev",nil)
- n_setfield(last,"next",nil)
- return first
-end
-
--- see node-nut.lua for more info on going nuts
-
-if not gonuts then
-
- local nuts = { }
- nodes.nuts = nuts
-
- local function dummy(f) return f end
-
- nodes.vianuts = dummy
- nodes.vianodes = dummy
-
- for k, v in next, nodes do
- if type(v) == "function" then
- nuts[k] = v
- end
- end
-
-end
-
--- also handy
-
-local tonode = nodes.tonode
-local whatsit_code = nodecodes.whatsit
-local getfields = node.fields
-local sort = table.sort
-local whatsitkeys = { }
-local keys = { whatsit = whatsitkeys }
-local messyhack = table.tohash { -- temporary solution
- nodecodes.attributelist,
- nodecodes.attribute,
- nodecodes.gluespec,
- nodecodes.action,
-}
-
-table.setmetatableindex(keys,function(t,k)
- local v = getfields(k)
- if messyhack[k] then
- for i=1,#v do
- if v[i] == "subtype" then
- remove(v,i)
- break
- end
- end
- end
- if v[ 0] then v[#v+1] = "next" v[ 0] = nil end
- if v[-1] then v[#v+1] = "prev" v[-1] = nil end
- sort(v)
- t[k] = v
- return v
-end)
-
-table.setmetatableindex(whatsitkeys,function(t,k)
- local v = getfields(whatsit_code,k)
- if v[ 0] then v[#v+1] = "next" v[ 0] = nil end
- if v[-1] then v[#v+1] = "prev" v[-1] = nil end
- sort(v)
- t[k] = v
- return v
-end)
-
-local function nodefields(n)
- n = tonode(n)
- local id = n.id
- if id == whatsit_code then
- return whatsitkeys[n.subtype]
- else
- return keys[id]
- end
-end
-
-nodes.keys = keys -- [id][subtype]
-nodes.fields = nodefields -- (n)