diff options
Diffstat (limited to 'tex/context/base/mkiv/cldf-lmt.lmt')
-rw-r--r-- | tex/context/base/mkiv/cldf-lmt.lmt | 720 |
1 files changed, 720 insertions, 0 deletions
diff --git a/tex/context/base/mkiv/cldf-lmt.lmt b/tex/context/base/mkiv/cldf-lmt.lmt new file mode 100644 index 000000000..b23ab1bd0 --- /dev/null +++ b/tex/context/base/mkiv/cldf-lmt.lmt @@ -0,0 +1,720 @@ +if not modules then modules = { } end modules ['cldf-lmt'] = { + version = 1.001, + comment = "companion to toks-scn.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local next, load = next, load + +local setmetatableindex = table.setmetatableindex +local setmetatablenewindex = table.setmetatablenewindex +local serialize = table.serialize + +local random = math.random +local randomseed = math.randomseed +local round = math.round +local abs = math.abs + +local implement = interfaces.implement + +local scanners = tokens.scanners +local scanword = scanners.word +local scanstring = scanners.string +local scanboolean = scanners.boolean +local scandimen = scanners.dimen +local scanfloat = scanners.float +local scaninteger = scanners.integer +local scannumber = scanners.luanumber +local scanluainteger = scanners.luainteger +local scanluacardinal = scanners.luacardinal +local scanluanumber = scanners.luanumber +local scanargument = scanners.argument +local scantoken = scanners.token +local scancsname = scanners.csname + +local getindex = token.get_index + +local texsetdimen = tex.setdimen +local texget = tex.get + +local values = tokens.values +local none_code = values.none +local integer_code = values.integer +local cardinal_code = values.cardinal +local dimension_code = values.dimension +local skip_code = values.skip +local boolean_code = values.boolean +local float_code = values.float + +local context = context + +-- variables -- + +local floats = { } +local integers = { } +local cardinals = { } +local numbers = { } + +implement { + name = "luafloat", + public = true, + value = true, + actions = function(b) + local n = scanword() + if b == "value" then + context("%.99g",floats[n] or 0) + else + floats[n] = scanluanumber(true) + -- floats[n] = scanfloat(true) + end + end, +} + +implement { + name = "luainteger", + public = true, + value = true, + actions = function(b) + local n = scanword() + if b == "value" then + context("%i",integers[n] or 0) + else + integers[n] = scanluainteger(true) + end + end, +} + +implement { + name = "luacount", + public = true, + value = true, + actions = function(b) + local n = scanword() + if b == "value" then + return integer_code, integers[n] or 0 + else + integers[n] = scaninteger(true) + end + end, +} + +implement { + name = "luadimen", + public = true, + value = true, + actions = function(b) + local n = scanword() + if b == "value" then + return dimension_code, integers[n] or 0 + else + integers[n] = scandimen(false,false,true) + end + end, +} + +implement { + name = "luacardinal", + public = true, + value = true, + actions = function(b) + local n = scanword() + if b == "value" then + context("%1.0f",cardinals[n] or 0) + else + cardinals[n] = scanluacardinal(true) + end + end, +} + +implement { + name = "luanumber", + public = true, + value = true, + actions = function(b) + local n = scanword() + if b == "value" then + context("%N",floats[n] or integers[n] or cardinals[n] or 0) -- maybe %N + else + -- floats[n] = scanfloat(true) + floats[n] = scanluanumber(true) + end + end, +} + +implement { + name = "luarandom", + public = true, + value = true, + actions = function(b) + if b == "value" then + return integer_code, random(scanluainteger(),scanluainteger()) + else + randomseed(scanluainteger(true)) + end + end, +} + +interfaces.floats = floats +interfaces.integers = integers +interfaces.cardinals = cardinals + +interfaces.numbers = table.setmetatableindex(function(t,k) + return floats[k] or integers[k] or cardinals[k] +end) + +-- arrays -- + +local arrays = { } + +interfaces.arrays = arrays + +local newindex = lua.newindex + +implement { + name = "newarray", + public = true, + protected = true, + arguments = { { + { "name", "string" }, + { "nx", "integer" }, + { "ny", "integer" }, + { "type", "string" }, + } }, + actions = function(t) + local name = t.name + if t.name then + local nx = t.nx + local ny = t.ny + local ty = t.type or "integer" + local df = nil + if ty == "integer" or ty == "float" or ty == "dimension" then + df = 0 + elseif ty == "boolean" then + df = false + else + ty = nil + end + if nx and ty ~= nil then + local data + if ny then + data = newindex(t.ny) + for i=1,ny do + data[i] = newindex(nx,df) + end + else + data = newindex(nx,df) + end + arrays[name] = data + data.nx = nx + data.ny = ny + data.type = ty + if ty == "integer" then + data.scanner = scaninteger + elseif ty == "boolean" then + data.scanner = scanboolean + elseif ty == "dimension" then + data.scanner = scandimen + elseif ty == "float" then + data.scanner = scanfloat + end + if ty == "integer" then + data.code = integer_code + elseif ty == "boolean" then + data.code = boolean_code + elseif ty == "dimension" then + data.code = dimension_code + elseif ty == "float" then + data.code = float_code + end + end + end + end, +} + +implement { + name = "arrayvalue", + public = true, + value = true, + actions = function(b) + local name = scanstring() + if name then + local a = arrays[name] + if a then + local nx = a.nx + local ny = a.ny + local d = a + if ny then + d = d[scaninteger()] + end + local x = scaninteger() + if b == "value" then + local code = a.code + if code == float_code then + context("%.99g",d[x]) + else + return code, d[x] + end + else + d[x] = a.scanner() + end + end + end + end, +} + +implement { + name = "arrayequals", + public = true, + value = true, + actions = function(b) + local name = scanstring() + if name then + local a = arrays[name] + if a then + local nx = a.nx + local ny = a.ny + local d = a + if ny then + d = d[scaninteger()] + end + local x = scaninteger() + if b == "value" then + return boolean_code, a.scanner() == d[x] + end + end + end + end, +} + +implement { + name = "arraycompare", + public = true, + value = true, + actions = function(b) + local name = scanstring() + if name then + local a = arrays[name] + if a then + local nx = a.nx + local ny = a.ny + local d = a + if ny then + d = d[scaninteger()] + end + local x = scaninteger() + if b == "value" then + local v = a.scanner() + local d = d[x] + if d < v then + return integer_code, 0 + elseif d == v then + return integer_code, 1 + else + return integer_code, 2 + end + end + end + end + end, +} + +implement { + name = "showarray", + public = true, + protected = true, + actions = function() + local name = scanstring() + if name then + inspect(arrays[name]) + end + end, +} + +-- expressions -- + +local cache = table.setmetatableindex(function(t,k) + local code = "return function() local n = interfaces.numbers local a = interfaces.arrays return " .. k .. " end" + code = loadstring(code) + if code then + code = code() + end + t[k] = code or false + return code +end) + +table.makeweak(cache) + +implement { + name = "luaexpression", + public = true, + actions = function() + local how = scanword() + local code = cache[scanargument()] + if code then + local result = code() + if result then + if not how then + context(tostring(code())) + elseif how == "float" then + context("%.99g",result) + elseif how == "integer" then + context("%i",round(result)) + elseif how == "cardinal" then + context("%d",abs(round(result))) + elseif how == "dimen" then + context("%p",result) + elseif how == "boolean" then + context("%d",result and 1 or 0) + elseif how == "lua" then + context("%q",result) + else + context(tostring(code())) + end + end + end + end +} + +local dimenfactors = number.dimenfactors + +implement { + name = "nodimen", + public = true, + value = true, + actions = function(b) + if b == "value" then + local how = scanword() + local what = scandimen() + if how then + local factor = dimenfactors[how] + if factor then + context("%.6N%s",factor*what,how) + else + return dimension_code, what + end + else + return dimension_code, what + end + else + local t = scantoken() + if t then + local i = getindex(t) + if i then + local d = scandimen(false,false,true) + texsetdimen(i,d) + end + end + end + end, +} + +-- experimental: + +local grouped = { } +local slots = { } +local nofslots = 0 +local nofgrouped = 0 + +local getdata = tokens.getdata +local setdata = tokens.setdata + +local report = logs.reporter("lua table") + +local ctxsprint = context.sprint + +-- we could have an extra one that collects all end of grouped actions +-- so that we dispose more in one go but it doesn's pay off + +local function newluatable(name,mt,dispose) + local g = { } + local t = slots[nofslots] + slots[nofslots] = false + nofslots = nofslots - 1 + if not t then + nofgrouped = nofgrouped + 1 + t = nofgrouped + end + if mt then + mt = getdata(name) + if mt then + mt = grouped[mt] + if mt then + setmetatableindex(g,mt) + end + end + end + grouped[t] = g + setdata(name,t) + -- This is the slow part. Doing this at the TeX end saved 10% runtime. I'll + -- think of something that we can set it at the Lua end. + if dispose then + ctxsprint("\\atendofgrouped{\\disposeluatable\\" .. name .. "}") + end +end + +local function disposeluatable(name) + local t = getdata(name) + local g = grouped[t] + if g then + grouped[t] = false + nofslots = nofslots + 1 + slots[nofslots] = t + end +end + +local function setluatable(name,kv) + local t = getdata(name) + local g = grouped[t] + if g and kv then + for k, v in next, kv do + g[k] = v + end + end +end + +local function getfromluatable(name,k) + local t = getdata(name) + local g = grouped[t] + if g then + local v = g[k] + if v then + context(v) + else + local n = tonumber(k) + if n then + local v = g[n] + if v then + context(v) + end + end + end + end +end + +local function idxfromluatable(name,k) + local t = getdata(name) + local g = grouped[t] + if g then + local v = g[k] + if v then + context(v) + end + end +end + +local function getluatable(name,k) + local t = getdata(name) + local g = grouped[t] + if g then + return g + end +end + +local function inspectluatable(name) + local t = getdata(name) + local g = grouped[t] + if g then + report("%s", serialize(g,'[grouped slot ' .. t .. ']')) + end +end + +local function showluatables() + report("nofgrouped %i, nofslots %i",nofgrouped,nofslots) + for t=1,nofgrouped do + local g = grouped[t] + if g then + report("%s", serialize(g,'[grouped slot ' .. t .. ']')) + end + end +end + +implement { + name = "newluatable", + protected = true, + -- public = true, + arguments = "csname", + actions = newluatable, +} + +implement { + name = "useluatable", + protected = true, + -- public = true, + arguments = { "csname", true }, + actions = newluatable, +} + +implement { + name = "disposeluatable", + protected = true, + public = true, + arguments = "csname", + actions = disposeluatable, +} + +implement { + name = "inspectluatable", + protected = true, + public = true, + arguments = "csname", + actions = inspectluatable, +} + +implement { + name = "showluatables", + protected = true, + public = true, + actions = showluatables, +} + +implement { + name = "setluatable", + protected = true, + public = true, + arguments = { "csname", "argument" }, + actions = function(name,data) + data = load("return {" .. data .. "}") + if data then + data = data() + if data then + setluatable(name,data) + end + end + end +} + +implement { + name = "getfromluatable", + protected = false, + public = true, + arguments = { "csname", "argument" }, + actions = getfromluatable, +} + +implement { + name = "idxfromluatable", + protected = false, + public = true, + arguments = { "csname", "integer" }, + actions = idxfromluatable, +} + +context.luatables = { + new = function(name) newluatable(name,false,true) end, + use = function(name) useluatable(name,true, true) end, + dispose = disposeluatable, + set = setluatable, + get = getluatable, + getfrom = getfromluatable, + idxfrom = idxfromluatable, + inspect = inspectluatable, + show = showluatables, +} + +-- Here's another mechanism ... + +local tables = { } +local stack = setmetatableindex("table") + +interfaces.implement { + name = "droptablegroup", + public = true, + actions = function() + local g = texget("currentgrouplevel") -- todo: tex.getgrouplevel() + local s = stack[g] + if s then + for t, data in next, s do + for k, v in next, data do + t[k] = v + end + end + stack[g] = { } + end + end, +} + +local ctx_atendofgroup = context.core.cs.atendofgroup +local ctx_droptablegroup = context.core.cs.droptablegroup + +local function handletable(t,b,array) + if b == "value" then + local k = array and scaninteger() or scanargument() + local v = t[k] + if v then + context(v) + end + else + local data = scanargument() + data = load("return {" .. data .. "}") + if data then + data = data() + if data then + local l = t.level + local g = texget("currentgrouplevel") -- todo: tex.getgrouplevel() + local s = stack[g] + local d = s[t] + if not d then + d = { } + s[t] = d + ctx_atendofgroup() + ctx_droptablegroup() + end + for k, v in next, data do + if not d[k] then + d[k] = t[k] + end + t[k] = v + end + if b == "global" then + for k, v in next, stack do + local t = s[t] + if t then + for k, v in next, data do + if t[k] then + t[k] = nil + end + end + end + end + end + end + end + end +end + +local function newtable(array) + local name = scancsname(true) + if not tables[name] then + local t = { } + tables[name] = t + interfaces.implement { + name = name, + public = true, + value = true, + actions = function(b) + handletable(t,b,array) + end, + } + else + -- already defined + end +end + +implement { + name = "newhashedtable", + protected = true, + public = true, + actions = newtable, +} + +implement { + name = "newindexedtable", + protected = true, + public = true, + actions = function() newtable(true) end, +} + +context.hashedtables = setmetatableindex(function(t,k) return tables[k] end) +context.indexedtables = context.hashedtables |