diff options
author | Marius <mariausol@gmail.com> | 2011-01-31 18:40:12 +0200 |
---|---|---|
committer | Marius <mariausol@gmail.com> | 2011-01-31 18:40:12 +0200 |
commit | 8f0a9674137499392552a70d470f614f0eb98b6c (patch) | |
tree | 6d67600678dc90e269c2800f9609e78f307254a1 /tex/context/base/mult-cld.lua | |
parent | cf65f174d2b790545f27134a5d41d39c942a1d5b (diff) | |
download | context-8f0a9674137499392552a70d470f614f0eb98b6c.tar.gz |
beta 2011.01.31 16:59
Diffstat (limited to 'tex/context/base/mult-cld.lua')
-rw-r--r-- | tex/context/base/mult-cld.lua | 753 |
1 files changed, 0 insertions, 753 deletions
diff --git a/tex/context/base/mult-cld.lua b/tex/context/base/mult-cld.lua deleted file mode 100644 index 08446a7ca..000000000 --- a/tex/context/base/mult-cld.lua +++ /dev/null @@ -1,753 +0,0 @@ -if not modules then modules = { } end modules ['mult-cld'] = { - version = 1.001, - comment = "companion to mult-cld.mkiv", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - --- This is an experiment: generating context code at the lua end. After all --- it is surprisingly simple to implement due to metatables. I was wondering --- if there was a more natural way to deal with commands at the lua end. --- Of course it's a bit slower but often more readable when mixed with lua --- code. It can also be handy when generating documents from databases or --- when constructing large tables or so. --- --- Todo: optional checking against interface --- Todo: coroutine trickery --- Todo: maybe use txtcatcodes - --- tflush needs checking ... sort of weird that it's not a table - --- __flushlines is an experiment and rather ugly so it will go away - -context = context or { } -local context = context - -local format, find, gmatch, splitlines = string.format, string.find, string.gmatch, string.splitlines -local next, type, tostring, setmetatable = next, type, tostring, setmetatable -local insert, remove, concat = table.insert, table.remove, table.concat -local lpegmatch = lpeg.match - -local tex = tex - -local texsprint = tex.sprint -local textprint = tex.tprint -local texprint = tex.print -local texiowrite = texio.write -local texcount = tex.count - -local isnode = node.is_node -- after 0.65 just node.type -local writenode = node.write -local copynodelist = node.copylist - -local ctxcatcodes = tex.ctxcatcodes -local prtcatcodes = tex.prtcatcodes -local texcatcodes = tex.texcatcodes -local txtcatcodes = tex.txtcatcodes -local vrbcatcodes = tex.vrbcatcodes -local xmlcatcodes = tex.xmlcatcodes - -local flush = texsprint - -local report_context = logs.new("context") -- here -local report_cld = logs.new("cld") - -local processlines = true -- experiments.register("context.processlines", function(v) processlines = v end) - --- for tracing it's easier to have two stacks - -local _stack_f_, _n_f_ = { }, 0 -local _stack_n_, _n_n_ = { }, 0 - -local function _store_f_(ti) - _n_f_ = _n_f_ + 1 - _stack_f_[_n_f_] = ti - return _n_f_ -end - -local function _store_n_(ti) - _n_n_ = _n_n_ + 1 - _stack_n_[_n_n_] = ti - return _n_n_ -end - -local function _flush_f_(n) - local sn = _stack_f_[n] - if not sn then - report_cld("data with id %s cannot be found on stack",n) - else - local tn = type(sn) - if tn == "function" then - if not sn() and texcount["@@trialtypesetting"] == 0 then -- @@trialtypesetting is private! - _stack_f_[n] = nil - else - -- keep, beware, that way the stack can grow - end - else - if texcount["@@trialtypesetting"] == 0 then -- @@trialtypesetting is private! - writenode(sn) - _stack_f_[n] = nil - else - writenode(copynodelist(sn)) - -- keep, beware, that way the stack can grow - end - end - end -end - -local function _flush_n_(n) - local sn = _stack_n_[n] - if not sn then - report_cld("data with id %s cannot be found on stack",n) - elseif texcount["@@trialtypesetting"] == 0 then -- @@trialtypesetting is private! - writenode(sn) - _stack_n_[n] = nil - else - writenode(copynodelist(sn)) - -- keep, beware, that way the stack can grow - end -end - -function context.restart() - _stack_f_, _n_f_ = { }, 0 - _stack_n_, _n_n_ = { }, 0 -end - -context._stack_f_ = _stack_f_ -context._store_f_ = _store_f_ -context._flush_f_ = _flush_f_ cldff = _flush_f_ - -context._stack_n_ = _stack_n_ -context._store_n_ = _store_n_ -context._flush_n_ = _flush_n_ cldfn = _flush_n_ - --- Should we keep the catcodes with the function? - -local catcodestack = { } -local currentcatcodes = ctxcatcodes -local contentcatcodes = ctxcatcodes - -local catcodes = { - ctx = ctxcatcodes, ctxcatcodes = ctxcatcodes, context = ctxcatcodes, - prt = prtcatcodes, prtcatcodes = prtcatcodes, protect = prtcatcodes, - tex = texcatcodes, texcatcodes = texcatcodes, plain = texcatcodes, - txt = txtcatcodes, txtcatcodes = txtcatcodes, text = txtcatcodes, - vrb = vrbcatcodes, vrbcatcodes = vrbcatcodes, verbatim = vrbcatcodes, - xml = xmlcatcodes, xmlcatcodes = xmlcatcodes, -} - -function context.pushcatcodes(c) - insert(catcodestack,currentcatcodes) - currentcatcodes = (c and catcodes[c] or tonumber(c)) or currentcatcodes - contentcatcodes = currentcatcodes -end - -function context.popcatcodes() - currentcatcodes = remove(catcodestack) or currentcatcodes - contentcatcodes = currentcatcodes -end - -function tex.fprint(...) -- goodie - texsprint(currentcatcodes,format(...)) -end - --- -- -- todo: tracing - -local newline = lpeg.patterns.newline -local space = lpeg.patterns.spacer -local spacing = newline * space^0 -local content = lpeg.C((1-spacing)^1) -local emptyline = space^0 * newline^2 -local endofline = space^0 * newline * space^0 -local simpleline = endofline * lpeg.P(-1) - -local function n_content(s) - flush(contentcatcodes,s) -end - -local function n_endofline() - texsprint(" \r") -end - -local function n_emptyline() - texprint("\r") -end - -local function n_simpleline() - texprint("\r") -end - -function lpeg.texlinesplitter(f_content,f_endofline,f_emptyline,f_simpleline) - local splitlines = - simpleline / (f_simpleline or n_simpleline) - + ( - emptyline / (f_emptyline or n_emptyline) - + endofline / (f_endofline or n_emptyline) - + content / (f_content or n_content) - )^0 - return function(str) return lpegmatch(splitlines,str) end -end - -local flushlines = lpeg.texlinesplitter(n_content,n_endofline,n_emptyline,n_simpleline) - -context.__flushlines = flushlines -- maybe context.helpers.flushtexlines -context.__flush = flush - -local printlines_ctx = ( - (newline) / function() texprint("") end + - (1-newline)^1 / function(s) texprint(ctxcatcodes,s) end * newline^-1 -)^0 - -local printlines_raw = ( - (newline) / function() texprint("") end + - (1-newline)^1 / function(s) texprint(s) end * newline^-1 -)^0 - -function context.printlines(str,raw) - if raw then - lpegmatch(printlines_raw,str) - else - lpegmatch(printlines_ctx,str) - end -end - --- -- -- - -local methodhandler = resolvers.methodhandler - -function context.viafile(data) - -- this is the only way to deal with nested buffers - -- and other catcode sensitive data - local filename = resolvers.savers.byscheme("virtual","viafile",data) - context.input(filename) -end - --- -- -- - -local function writer(parent,command,first,...) - local t = { first, ... } - flush(currentcatcodes,command) -- todo: ctx|prt|texcatcodes - local direct = false - for i=1,#t do - local ti = t[i] - local typ = type(ti) - if direct then - if typ == "string" or typ == "number" then - flush(currentcatcodes,ti) - else -- node.write - report_context("error: invalid use of direct in '%s', only strings and numbers can be flushed directly, not '%s'",command,typ) - end - direct = false - elseif ti == nil then - -- nothing - elseif ti == "" then - flush(currentcatcodes,"{}") - elseif typ == "string" then - if processlines and find(ti,"[\n\r]") then -- we can check for ti == "\n" - flush(currentcatcodes,"{") - local flushlines = parent.__flushlines or flushlines - flushlines(ti) - flush(currentcatcodes,"}") - elseif currentcatcodes == contentcatcodes then - flush(currentcatcodes,"{",ti,"}") - else - flush(currentcatcodes,"{") - flush(contentcatcodes,ti) - flush(currentcatcodes,"}") - end - elseif typ == "number" then - -- numbers never have funny catcodes - flush(currentcatcodes,"{",ti,"}") - elseif typ == "table" then - local tn = #ti - if tn == 0 then - local done = false - for k, v in next, ti do - if done then - if v == "" then - flush(currentcatcodes,",",k,'=') - else - flush(currentcatcodes,",",k,'=',v) - end - else - if v == "" then - flush(currentcatcodes,"[",k,'=') - else - flush(currentcatcodes,"[",k,'=',v) - end - done = true - end - end - flush(currentcatcodes,"]") - elseif tn == 1 then -- some 20% faster than the next loop - local tj = ti[1] - if type(tj) == "function" then - flush(currentcatcodes,"[\\cldff{",_store_f_(tj),"}]") - else - flush(currentcatcodes,"[",tj,"]") - end - else -- is concat really faster than flushes here? probably needed anyway (print artifacts) - for j=1,tn do - local tj = ti[j] - if type(tj) == "function" then - ti[j] = "\\cldff{" .. _store_f_(tj) .. "}" - end - end - flush(currentcatcodes,"[",concat(ti,","),"]") - end - elseif typ == "function" then - flush(currentcatcodes,"{\\cldff{",_store_f_(ti),"}}") -- todo: ctx|prt|texcatcodes - elseif typ == "boolean" then - if ti then - -- flush(currentcatcodes,"^^M") - texprint("") - else - direct = true - end - elseif typ == "thread" then - report_context("coroutines not supported as we cannot yield across boundaries") - elseif isnode(ti) then -- slow - flush(currentcatcodes,"{\\cldfn{",_store_n_(ti),"}}") - else - report_context("error: '%s' gets a weird argument '%s'",command,tostring(ti)) - end - end -end - -local generics = { } context.generics = generics - -local function indexer(parent,k) - local c = "\\" .. tostring(generics[k] or k) - local f = function(first,...) - if first == nil then - flush(currentcatcodes,c) - else - return writer(parent,c,first,...) - end - end - parent[k] = f - return f -end - -local function caller(parent,f,a,...) - if not parent then - -- so we don't need to test in the calling (slower but often no issue) (will go) - elseif f ~= nil then - local typ = type(f) - if typ == "string" then - if a then - flush(contentcatcodes,format(f,a,...)) -- was currentcatcodes - elseif processlines and find(f,"[\n\r]") then - local flushlines = parent.__flushlines or flushlines - flushlines(f) - else - flush(contentcatcodes,f) - end - elseif typ == "number" then - if a then - flush(currentcatcodes,f,a,...) - else - flush(currentcatcodes,f) - end - elseif typ == "function" then - -- ignored: a ... - flush(currentcatcodes,"{\\cldff{",_store_f_(f),"}}") -- todo: ctx|prt|texcatcodes - elseif typ == "boolean" then - if f then - if a ~= nil then - local flushlines = parent.__flushlines or flushlines - flushlines(f) - -- ignore ... maybe some day - else - -- flush(currentcatcodes,"^^M") - texprint("") - end - else - if a ~= nil then - -- no command, same as context(a,...) - writer(parent,"",a,...) - else - -- ignored - end - end - elseif typ == "thread" then - report_context("coroutines not supported as we cannot yield across boundaries") - elseif isnode(f) then -- slow - -- writenode(f) - flush(currentcatcodes,"\\cldfn{",_store_n_(f),"}") - else - report_context("error: 'context' gets a weird argument '%s'",tostring(f)) - end - end -end - -local defaultcaller = caller - -setmetatable(context, { __index = indexer, __call = caller } ) - --- now we tweak unprotect and protect - -function context.unprotect() - -- at the lua end - insert(catcodestack,currentcatcodes) - currentcatcodes = prtcatcodes - contentcatcodes = currentcatcodes - -- at the tex end - flush("\\unprotect") -end - -function context.protect() - -- at the tex end - flush("\\protect") - -- at the lua end - currentcatcodes = remove(catcodestack) or currentcatcodes - contentcatcodes = currentcatcodes -end - --- logging - -local trace_stack = { } - -local normalflush = flush -local normalwriter = writer -local currenttrace = nil -local nofwriters = 0 -local nofflushes = 0 - -statistics.register("traced context", function() - if nofwriters > 0 or nofflushes > 0 then - return format("writers: %s, flushes: %s, maxstack: %s",nofwriters,nofflushes,_n_f_) - end -end) - -local tracedwriter = function(parent,...) - nofwriters = nofwriters + 1 - local t, f, n = { "w : " }, flush, 0 - flush = function(...) - n = n + 1 - t[n] = concat({...},"",2) - normalflush(...) - end - normalwriter(parent,...) - flush = f - currenttrace(concat(t)) -end - -local tracedflush = function(...) - nofflushes = nofflushes + 1 - normalflush(...) - local t = { ... } - t[1] = "f : " -- replaces the catcode - for i=2,#t do - local ti = t[i] - local tt = type(ti) - if tt == "string" then - -- ok - elseif tt == "number" then - -- ok - else - t[i] = format("<%s>",tostring(ti)) - end - -- currenttrace(format("%02i: %s",i-1,tostring(t[i]))) - end - currenttrace(concat(t)) -end - -local function pushlogger(trace) - insert(trace_stack,currenttrace) - currenttrace = trace - flush, writer = tracedflush, tracedwriter - context.__flush = flush -end - -local function poplogger() - currenttrace = remove(trace_stack) - if not currenttrace then - flush, writer = normalflush, normalwriter - context.__flush = flush - end -end - -local function settracing(v) - if v then - pushlogger(report_context) - else - poplogger() - end -end - --- todo: share flushers so that we can define in other files - -trackers.register("context.trace",settracing) - -context.pushlogger = pushlogger -context.poplogger = poplogger -context.settracing = settracing - -local trace_cld = false trackers.register("context.files", function(v) trace_cld = v end) - -function context.runfile(filename) - local foundname = resolvers.findtexfile(file.addsuffix(filename,"cld")) or "" - if foundname ~= "" then - local ok = dofile(foundname) - if type(ok) == "function" then - if trace_cld then - report_context("begin of file '%s' (function call)",foundname) - end - ok() - if trace_cld then - report_context("end of file '%s' (function call)",foundname) - end - elseif ok then - report_context("file '%s' is processed and returns true",foundname) - else - report_context("file '%s' is processed and returns nothing",foundname) - end - else - report_context("unknown file '%s'",filename) - end -end - --- some functions - -function context.direct(first,...) - if first ~= nil then - return writer(context,"",first,...) - end -end - --- context.delayed (todo: lines) - -local delayed = { } context.delayed = delayed -- maybe also store them - -local function indexer(parent,k) - local f = function(...) - local a = { ... } - return function() - return context[k](unpack(a)) - end - end - parent[k] = f - return f -end - -local function caller(parent,...) -- todo: nodes - local a = { ... } - return function() - return context(unpack(a)) - end -end - -setmetatable(delayed, { __index = indexer, __call = caller } ) - --- context.nested (todo: lines) - -local nested = { } context.nested = nested - -local function indexer(parent,k) - local f = function(...) - local t, savedflush, n = { }, flush, 0 - flush = function(c,f,s,...) -- catcodes are ignored - n = n + 1 - t[n] = s and concat{f,s,...} or f -- optimized for #args == 1 - end - context[k](...) - flush = savedflush - return concat(t) - end - parent[k] = f - return f -end - -local function caller(parent,...) - local t, savedflush, n = { }, flush, 0 - flush = function(c,f,s,...) -- catcodes are ignored - n = n + 1 - t[n] = s and concat{f,s,...} or f -- optimized for #args == 1 - end - context(...) - flush = savedflush - return concat(t) -end - -setmetatable(nested, { __index = indexer, __call = caller } ) - --- verbatim - -local verbatim = { } context.verbatim = verbatim - -local function indexer(parent,k) - local command = context[k] - local f = function(...) - local savedcatcodes = contentcatcodes - contentcatcodes = vrbcatcodes - command(...) - contentcatcodes = savedcatcodes - end - parent[k] = f - return f -end - -local function caller(parent,...) - local savedcatcodes = contentcatcodes - contentcatcodes = vrbcatcodes - defaultcaller(parent,...) - contentcatcodes = savedcatcodes -end - -setmetatable(verbatim, { __index = indexer, __call = caller } ) - --- metafun - -local metafun = { } context.metafun = metafun - -local mpdrawing = "\\MPdrawing" - -local function caller(parent,f,a,...) - if not parent then - -- skip - elseif f then - local typ = type(f) - if typ == "string" then - if a then - flush(currentcatcodes,mpdrawing,"{",format(f,a,...),"}") - else - flush(currentcatcodes,mpdrawing,"{",f,"}") - end - elseif typ == "number" then - if a then - flush(currentcatcodes,mpdrawing,"{",f,a,...,"}") - else - flush(currentcatcodes,mpdrawing,"{",f,"}") - end - elseif typ == "function" then - -- ignored: a ... - flush(currentcatcodes,mpdrawing,"{\\cldff{",store_(f),"}}") - elseif typ == "boolean" then - -- ignored: a ... - if f then - flush(currentcatcodes,mpdrawing,"{^^M}") - else - report_context("warning: 'metafun' gets argument 'false' which is currently unsupported") - end - else - report_context("error: 'metafun' gets a weird argument '%s'",tostring(f)) - end - end -end - -setmetatable(metafun, { __call = caller } ) - -function metafun.start() - context.resetMPdrawing() -end - -function metafun.stop() - context.MPdrawingdonetrue() - context.getMPdrawing() -end - -function metafun.color(name) - return format([[\MPcolor{%s}]],name) -end - --- metafun.delayed - -local delayed = { } metafun.delayed = delayed - -local function indexer(parent,k) - local f = function(...) - local a = { ... } - return function() - return metafun[k](unpack(a)) - end - end - parent[k] = f - return f -end - - -local function caller(parent,...) - local a = { ... } - return function() - return metafun(unpack(a)) - end -end - -setmetatable(delayed, { __index = indexer, __call = caller } ) - ---~ Not that useful yet. Maybe something like this when the main loop ---~ is a coroutine. It also does not help taking care of nested calls. ---~ Even worse, it interferes with other mechanisms using context calls. ---~ ---~ local create, yield, resume = coroutine.create, coroutine.yield, coroutine.resume ---~ local getflush, setflush = context.getflush, context.setflush ---~ local texsprint, ctxcatcodes = tex.sprint, tex.ctxcatcodes ---~ ---~ function context.getflush() ---~ return flush ---~ end ---~ ---~ function context.setflush(newflush) ---~ local oldflush = flush ---~ flush = newflush or flush ---~ return oldflush ---~ end ---~ ---~ function context.direct(f) ---~ local routine = create(f) ---~ local oldflush = getflush() ---~ function newflush(...) ---~ oldflush(...) ---~ yield(true) ---~ end ---~ setflush(newflush) ---~ ---~ -- local function resumecontext() ---~ -- local done = resume(routine) ---~ -- if not done then ---~ -- return ---~ -- end ---~ -- resumecontext() -- stack overflow ... no tail recursion ---~ -- end ---~ -- context.resume = resumecontext ---~ -- texsprint(ctxcatcodes,"\\ctxlua{context.resume()}") ---~ ---~ local function resumecontext() ---~ local done = resume(routine) ---~ if not done then ---~ return ---~ end ---~ -- texsprint(ctxcatcodes,"\\exitloop") ---~ texsprint(ctxcatcodes,"\\ctxlua{context.resume()}") -- can be simple macro call ---~ end ---~ context.resume = resumecontext ---~ -- texsprint(ctxcatcodes,"\\doloop{\\ctxlua{context.resume()}}") -- can be fast loop at the tex end ---~ texsprint(ctxcatcodes,"\\ctxlua{context.resume()}") ---~ ---~ end ---~ ---~ function something() ---~ context("\\setbox0") ---~ context("\\hbox{hans hagen xx}") ---~ context("\\the\\wd0/\\box0") ---~ end ---~ ---~ context.direct(something) - --- helpers: - -function context.concat(t,separator) - local done = false - for i=1,#t do - local ti = t[i] - if ti ~= "" then - if done then - context(separator) - end - context(ti) - done = true - end - end -end |