summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/mkiv/util-seq.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/context/base/mkiv/util-seq.lua')
-rw-r--r--Master/texmf-dist/tex/context/base/mkiv/util-seq.lua370
1 files changed, 216 insertions, 154 deletions
diff --git a/Master/texmf-dist/tex/context/base/mkiv/util-seq.lua b/Master/texmf-dist/tex/context/base/mkiv/util-seq.lua
index d302ff276f1..e7a503fafcd 100644
--- a/Master/texmf-dist/tex/context/base/mkiv/util-seq.lua
+++ b/Master/texmf-dist/tex/context/base/mkiv/util-seq.lua
@@ -17,26 +17,39 @@ use locals to refer to them when compiling the chain.</p>
-- todo: protect groups (as in tasks)
-local gsub, concat, gmatch = string.gsub, table.concat, string.gmatch
-local type, load = type, load
+local gsub, gmatch = string.gsub, string.gmatch
+local concat, sortedkeys = table.concat, table.sortedkeys
+local type, load, next, tostring = type, load, next, tostring
-utilities = utilities or { }
-local tables = utilities.tables
-local allocate = utilities.storage.allocate
+utilities = utilities or { }
+local tables = utilities.tables
+local allocate = utilities.storage.allocate
-local formatters = string.formatters
+local formatters = string.formatters
+local replacer = utilities.templates.replacer
-local sequencers = { }
-utilities.sequencers = sequencers
+local trace_used = false
+local trace_detail = false
+local report = logs.reporter("sequencer")
+local usedcount = 0
+local usednames = { }
-local functions = allocate()
-sequencers.functions = functions
+trackers.register("sequencers.used", function(v) trace_used = true end)
+trackers.register("sequencers.detail",function(v) trace_detail = true end)
+
+local sequencers = { }
+utilities.sequencers = sequencers
+
+local functions = allocate()
+sequencers.functions = functions
local removevalue = tables.removevalue
local replacevalue = tables.replacevalue
local insertaftervalue = tables.insertaftervalue
local insertbeforevalue = tables.insertbeforevalue
+local usedsequences = { }
+
local function validaction(action)
if type(action) == "string" then
local g = _G
@@ -63,9 +76,11 @@ function sequencers.new(t) -- was reset
gskip = { },
dirty = true,
runner = nil,
+ steps = 0,
}
if t then
s.arguments = t.arguments
+ s.templates = t.templates
s.returnvalues = t.returnvalues
s.results = t.results
local name = t.name
@@ -86,120 +101,142 @@ function sequencers.new(t) -- was reset
end
function sequencers.prependgroup(t,group,where)
- t = known[t]
- if t then
- local order = t.order
- removevalue(order,group)
- insertbeforevalue(order,where,group)
- t.list[group] = { }
- t.dirty = true
- t.runner = nil
+ if t and group then
+ t = known[t]
+ if t then
+ local order = t.order
+ removevalue(order,group)
+ insertbeforevalue(order,where,group)
+ t.list[group] = { }
+ t.dirty = true
+ t.runner = nil
+ end
end
end
function sequencers.appendgroup(t,group,where)
- t = known[t]
- if t then
- local order = t.order
- removevalue(order,group)
- insertaftervalue(order,where,group)
- t.list[group] = { }
- t.dirty = true
- t.runner = nil
+ if t and group then
+ t = known[t]
+ if t then
+ local order = t.order
+ removevalue(order,group)
+ insertaftervalue(order,where,group)
+ t.list[group] = { }
+ t.dirty = true
+ t.runner = nil
+ end
end
end
function sequencers.prependaction(t,group,action,where,kind,force)
- t = known[t]
- if t then
- local g = t.list[group]
- if g and (force or validaction(action)) then
- removevalue(g,action)
- insertbeforevalue(g,where,action)
- t.kind[action] = kind
- t.dirty = true
- t.runner = nil
+ if t and group and action then
+ t = known[t]
+ if t then
+ local g = t.list[group]
+ if g and (force or validaction(action)) then
+ removevalue(g,action)
+ insertbeforevalue(g,where,action)
+ t.kind[action] = kind
+ t.dirty = true
+ t.runner = nil
+ end
end
end
end
function sequencers.appendaction(t,group,action,where,kind,force)
- t = known[t]
- if t then
- local g = t.list[group]
- if g and (force or validaction(action)) then
- removevalue(g,action)
- insertaftervalue(g,where,action)
- t.kind[action] = kind
- t.dirty = true
- t.runner = nil
+ if t and group and action then
+ t = known[t]
+ if t then
+ local g = t.list[group]
+ if g and (force or validaction(action)) then
+ removevalue(g,action)
+ insertaftervalue(g,where,action)
+ t.kind[action] = kind
+ t.dirty = true
+ t.runner = nil
+ end
end
end
end
function sequencers.enableaction(t,action)
- t = known[t]
- if t then
- t.askip[action] = false
- t.dirty = true
- t.runner = nil
+ if t and action then
+ t = known[t]
+ if t then
+ t.askip[action] = false
+ t.dirty = true
+ t.runner = nil
+ end
end
end
function sequencers.disableaction(t,action)
- t = known[t]
- if t then
- t.askip[action] = true
- t.dirty = true
- t.runner = nil
+ if t and action then
+ t = known[t]
+ if t then
+ t.askip[action] = true
+ t.dirty = true
+ t.runner = nil
+ end
end
end
function sequencers.enablegroup(t,group)
- t = known[t]
- if t then
- t.gskip[action] = false
- t.dirty = true
- t.runner = nil
+ if t and group then
+ t = known[t]
+ if t then
+ t.gskip[group] = false
+ t.dirty = true
+ t.runner = nil
+ end
end
end
function sequencers.disablegroup(t,group)
- t = known[t]
- if t then
- t.gskip[action] = true
- t.dirty = true
- t.runner = nil
+ if t and group then
+ t = known[t]
+ if t then
+ t.gskip[group] = true
+ t.dirty = true
+ t.runner = nil
+ end
end
end
function sequencers.setkind(t,action,kind)
- t = known[t]
- if t then
- t.kind[action] = kind
- t.dirty = true
- t.runner = nil
+ if t and action then
+ t = known[t]
+ if t then
+ t.kind[action] = kind
+ t.dirty = true
+ t.runner = nil
+ end
end
end
function sequencers.removeaction(t,group,action,force)
- t = known[t]
- local g = t and t.list[group]
- if g and (force or validaction(action)) then
- removevalue(g,action)
- t.dirty = true
- t.runner = nil
+ if t and group and action then
+ t = known[t]
+ local g = t and t.list[group]
+ if g and (force or validaction(action)) then
+ removevalue(g,action)
+ t.dirty = true
+ t.runner = nil
+ end
end
end
function sequencers.replaceaction(t,group,oldaction,newaction,force)
- t = known[t]
- if t then
- local g = t.list[group]
- if g and (force or validaction(oldaction)) then
- replacevalue(g,oldaction,newaction)
- t.dirty = true
- t.runner = nil
+ if t and group and oldaction and newaction then
+ t = known[t]
+ if t then
+ local g = t.list[group]
+ if g and (force or validaction(oldaction)) then
+ replacevalue(g,oldaction,newaction)
+ t.dirty = true
+ t.runner = nil
+ end
end
end
end
@@ -209,9 +246,19 @@ local function localize(str)
end
local function construct(t)
- local list, order, kind, gskip, askip = t.list, t.order, t.kind, t.gskip, t.askip
- local arguments, returnvalues, results = t.arguments or "...", t.returnvalues, t.results
- local variables, calls, n = { }, { }, 0
+ local list = t.list
+ local order = t.order
+ local kind = t.kind
+ local gskip = t.gskip
+ local askip = t.askip
+ local name = t.name or "?"
+ local arguments = t.arguments or "..."
+ local returnvalues = t.returnvalues
+ local results = t.results
+ local variables = { }
+ local calls = { }
+ local n = 0
+ usedcount = usedcount + 1
for i=1,#order do
local group = order[i]
if not gskip[group] then
@@ -219,6 +266,11 @@ local function construct(t)
for i=1,#actions do
local action = actions[i]
if not askip[action] then
+ if trace_used then
+ local action = tostring(action)
+ report("%02i: category %a, group %a, action %a",usedcount,name,group,action)
+ usednames[action] = true
+ end
local localized
if type(action) == "function" then
local name = localize(tostring(action))
@@ -242,6 +294,7 @@ local function construct(t)
end
end
t.dirty = false
+ t.steps = n
if n == 0 then
t.compiled = ""
else
@@ -253,30 +306,27 @@ local function construct(t)
t.compiled = formatters["%s\nreturn function(%s)\n%s\nend"](variables,arguments,calls)
end
end
--- print(t.compiled)
return t.compiled -- also stored so that we can trace
end
sequencers.tostring = construct
sequencers.localize = localize
-compile = function(t,compiler,n) -- already referred to in sequencers.new
+compile = function(t,compiler,...) -- already referred to in sequencers.new
local compiled
if not t or type(t) == "string" then
- -- weird ... t.compiled = t .. so
return false
end
if compiler then
- compiled = compiler(t,n)
+ compiled = compiler(t,...)
t.compiled = compiled
else
- compiled = construct(t,n)
+ compiled = construct(t,...)
end
local runner
if compiled == "" then
runner = false
else
--- inspect(compiled)
runner = compiled and load(compiled)() -- we can use loadstripped here
end
t.runner = runner
@@ -285,52 +335,45 @@ end
sequencers.compile = compile
--- we used to deal with tail as well but now that the lists are always
--- double linked and the kernel function no longer expect tail as
--- argument we stick to head and done (done can probably also go
--- as luatex deals with return values efficiently now .. in the
--- past there was some copying involved, but no longer)
-
--- todo: use sequencer (can have arguments and returnvalues etc now)
-
-local template_yes_state = [[
-%s
-return function(head%s)
- local ok, done = false, false
-%s
- return head, done
-end]]
-
-local template_yes_nostate = [[
-%s
-return function(head%s)
-%s
- return head, true
-end]]
-
-local template_nop = [[
-return function()
- return false, false
-end]]
-
-function sequencers.nodeprocessor(t,nofarguments) -- todo: handle 'kind' in plug into tostring
- local list, order, kind, gskip, askip = t.list, t.order, t.kind, t.gskip, t.askip
- local nostate = t.nostate
- local vars, calls, args, n = { }, { }, nil, 0
- if nofarguments == 0 then
- args = ""
- elseif nofarguments == 1 then
- args = ",one"
- elseif nofarguments == 2 then
- args = ",one,two"
- elseif nofarguments == 3 then -- from here on probably slower than ...
- args = ",one,two,three"
- elseif nofarguments == 4 then
- args = ",one,two,three,four"
- elseif nofarguments == 5 then
- args = ",one,two,three,four,five"
- else
- args = ",..."
+function sequencers.nodeprocessor(t,nofarguments)
+ --
+ local templates = nofarguments
+ --
+ if type(templates) ~= "table" then
+ return ""
+ end
+ --
+ local replacers = { }
+ for k, v in next, templates do
+ replacers[k] = replacer(v)
+ end
+ --
+ local construct = replacers.process
+ local step = replacers.step
+ if not construct or not step then
+ return ""
+ end
+ --
+ local calls = { }
+ local aliases = { }
+ local ncalls = 0
+ local naliases = 0
+ local f_alias = formatters["local %s = %s"]
+ --
+ local list = t.list
+ local order = t.order
+ local kind = t.kind
+ local gskip = t.gskip
+ local askip = t.askip
+ local name = t.name or "?"
+ local steps = 0
+ usedcount = usedcount + 1
+ --
+ if trace_detail then
+ naliases = naliases + 1
+ aliases[naliases] = formatters["local report = logs.reporter('sequencer',%q)"](name)
+ ncalls = ncalls + 1
+ calls[ncalls] = [[report("start")]]
end
for i=1,#order do
local group = order[i]
@@ -339,28 +382,47 @@ function sequencers.nodeprocessor(t,nofarguments) -- todo: handle 'kind' in plug
for i=1,#actions do
local action = actions[i]
if not askip[action] then
- local localized = localize(action)
- n = n + 1
- vars[n] = formatters["local %s = %s"](localized,action)
- -- only difference with tostring is kind and rets (why no return)
- if nostate then
- if kind[action] == "nohead" then
- calls[n] = formatters[" %s(head%s)"](localized,args)
- else
- calls[n] = formatters[" head = %s(head%s)"](localized,args)
- end
- else
- if kind[action] == "nohead" then
- calls[n] = formatters[" ok = %s(head%s) if ok then done = true end"](localized,args)
- else
- calls[n] = formatters[" head, ok = %s(head%s) if ok then done = true end"](localized,args)
- end
+ steps = steps + 1
+ if trace_used or trace_detail then
+ local action = tostring(action)
+ report("%02i: category %a, group %a, action %a",usedcount,name,group,action)
+ usednames[action] = true
end
+ if trace_detail then
+ ncalls = ncalls + 1
+ calls[ncalls] = formatters[ [[report(" step %a, action %a")]] ](steps,tostring(action))
+ end
+ local localized = localize(action)
+ local onestep = replacers[kind[action]] or step
+ naliases = naliases + 1
+ ncalls = ncalls + 1
+ aliases[naliases] = f_alias(localized,action)
+ calls [ncalls] = onestep { action = localized }
end
end
end
end
- local processor = #calls > 0 and formatters[nostate and template_yes_nostate or template_yes_state](concat(vars,"\n"),args,concat(calls,"\n")) or template_nop
+ t.steps = steps
+ local processor
+ if steps == 0 then
+ processor = templates.default or construct { }
+ else
+ if trace_detail then
+ ncalls = ncalls + 1
+ calls[ncalls] = [[report("stop")]]
+ end
+ processor = construct {
+ localize = concat(aliases,"\n"),
+ actions = concat(calls,"\n"),
+ }
+ end
+ -- processor = "print('running : " .. (t.name or "?") .. "')\n" .. processor
-- print(processor)
return processor
end
+
+statistics.register("used sequences",function()
+ if next(usednames) then
+ return concat(sortedkeys(usednames)," ")
+ end
+end)