From 8d8d528d2ad52599f11250cfc567fea4f37f2a8b Mon Sep 17 00:00:00 2001 From: Context Git Mirror Bot Date: Tue, 12 Jan 2016 17:15:07 +0100 Subject: 2016-01-12 16:26:00 --- tex/context/base/mkiv/mlib-lua.lua | 394 +++++++++++++++++++++++++++++++++++++ 1 file changed, 394 insertions(+) create mode 100644 tex/context/base/mkiv/mlib-lua.lua (limited to 'tex/context/base/mkiv/mlib-lua.lua') diff --git a/tex/context/base/mkiv/mlib-lua.lua b/tex/context/base/mkiv/mlib-lua.lua new file mode 100644 index 000000000..e7f8f9cc5 --- /dev/null +++ b/tex/context/base/mkiv/mlib-lua.lua @@ -0,0 +1,394 @@ +if not modules then modules = { } end modules ['mlib-lua'] = { + version = 1.001, + comment = "companion to mlib-ctx.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files", +} + +-- This is very preliminary code! + +-- maybe we need mplib.model, but how with instances + +local type, tostring, select, loadstring = type, tostring, select, loadstring +local find, gsub = string.find, string.gsub + +local formatters = string.formatters +local concat = table.concat +local lpegmatch = lpeg.match + +local P, S, Ct = lpeg.P, lpeg.S, lpeg.Ct + +local report_luarun = logs.reporter("metapost","lua") +local report_message = logs.reporter("metapost") + +local trace_luarun = false trackers.register("metapost.lua",function(v) trace_luarun = v end) +local trace_enabled = true + +local be_tolerant = true directives.register("metapost.lua.tolerant",function(v) be_tolerant = v end) + +mp = mp or { } -- system namespace +MP = MP or { } -- user namespace + +local buffer, n, max = { }, 0, 10 -- we reuse upto max + +function mp._f_() + if trace_enabled and trace_luarun then + local result = concat(buffer," ",1,n) + if n > max then + buffer = { } + end + n = 0 + report_luarun("data: %s",result) + return result + else + if n == 0 then + return "" + end + local result + if n == 1 then + result = buffer[1] + else + result = concat(buffer," ",1,n) + end + if n > max then + buffer = { } + end + n = 0 + return result + end +end + +local f_code = formatters["%s return mp._f_()"] + +local f_numeric = formatters["%.16f"] +local f_pair = formatters["(%.16f,%.16f)"] +local f_triplet = formatters["(%.16f,%.16f,%.16f)"] +local f_quadruple = formatters["(%.16f,%.16f,%.16f,%.16f)"] + +function mp.print(...) + for i=1,select("#",...) do + local value = select(i,...) + if value ~= nil then + n = n + 1 + local t = type(value) + if t == "number" then + buffer[n] = f_numeric(value) + elseif t == "string" then + buffer[n] = value + elseif t == "table" then + buffer[n] = "(" .. concat(value,",") .. ")" + else -- boolean or whatever + buffer[n] = tostring(value) + end + end + end +end + +function mp.boolean(n) + n = n + 1 + buffer[n] = n and "true" or "false" +end + +function mp.numeric(n) + n = n + 1 + buffer[n] = n and f_numeric(n) or "0" +end + +function mp.pair(x,y) + n = n + 1 + if type(x) == "table" then + buffer[n] = f_pair(x[1],x[2]) + else + buffer[n] = f_pair(x,y) + end +end + +function mp.triplet(x,y,z) + n = n + 1 + if type(x) == "table" then + buffer[n] = f_triplet(x[1],x[2],x[3]) + else + buffer[n] = f_triplet(x,y,z) + end +end + +function mp.quadruple(w,x,y,z) + n = n + 1 + if type(w) == "table" then + buffer[n] = f_quadruple(w[1],w[2],w[3],w[4]) + else + buffer[n] = f_quadruple(w,x,y,z) + end +end + +function mp.path(t,connector,cycle) + if type(t) == "table" then + local tn = #t + if tn > 0 then + if connector == true then + connector = "--" + cycle = true + elseif not connector then + connector = "--" + end + local ti = t[1] + n = n + 1 ; buffer[n] = f_pair(ti[1],ti[2]) + for i=2,tn do + local ti = t[i] + n = n + 1 ; buffer[n] = connector + n = n + 1 ; buffer[n] = f_pair(ti[1],ti[2]) + end + if cycle then + n = n + 1 ; buffer[n] = connector + n = n + 1 ; buffer[n] = "cycle" + end + end + end +end + +function mp.size(t) + n = n + 1 + buffer[n] = type(t) == "table" and f_numeric(#t) or "0" +end + +-- experiment: names can change + +local datasets = { } +mp.datasets = datasets + +function datasets.load(tag,filename) + if not filename then + tag, filename = file.basename(tag), tag + end + local data = mp.dataset(io.loaddata(filename) or "") + datasets[tag] = { + Data = data, + Line = function(n) mp.path(data[n or 1]) end, + Size = function() mp.size(data) end, + } +end + +-- + +local replacer = lpeg.replacer("@","%%") + +function mp.format(fmt,...) + n = n + 1 + if not find(fmt,"%%") then + fmt = lpegmatch(replacer,fmt) + end + buffer[n] = formatters[fmt](...) +end + +function mp.quoted(fmt,s,...) + n = n + 1 + if s then + if not find(fmt,"%%") then + fmt = lpegmatch(replacer,fmt) + end + buffer[n] = '"' .. formatters[fmt](s,...) .. '"' + elseif fmt then + buffer[n] = '"' .. fmt .. '"' + else + -- something is wrong + end +end + +function mp.n(t) + return type(t) == "table" and #t or 0 +end + +local whitespace = lpeg.patterns.whitespace +local newline = lpeg.patterns.newline +local setsep = newline^2 +local comment = (S("#%") + P("--")) * (1-newline)^0 * (whitespace - setsep)^0 +local value = (1-whitespace)^1 / tonumber +local entry = Ct( value * whitespace * value) +local set = Ct((entry * (whitespace-setsep)^0 * comment^0)^1) +local series = Ct((set * whitespace^0)^1) + +local pattern = whitespace^0 * series + +function mp.dataset(str) + return lpegmatch(pattern,str) +end + +-- \startluacode +-- local str = [[ +-- 10 20 20 20 +-- 30 40 40 60 +-- 50 10 +-- +-- 10 10 20 30 +-- 30 50 40 50 +-- 50 20 -- the last one +-- +-- 10 20 % comment +-- 20 10 +-- 30 40 # comment +-- 40 20 +-- 50 10 +-- ]] +-- +-- MP.myset = mp.dataset(str) +-- +-- inspect(MP.myset) +-- \stopluacode +-- +-- \startMPpage +-- color c[] ; c[1] := red ; c[2] := green ; c[3] := blue ; +-- for i=1 upto lua("mp.print(mp.n(MP.myset))") : +-- draw lua("mp.path(MP.myset[" & decimal i & "])") withcolor c[i] ; +-- endfor ; +-- \stopMPpage + +-- function metapost.runscript(code) +-- local f = loadstring(f_code(code)) +-- if f then +-- local result = f() +-- if result then +-- local t = type(result) +-- if t == "number" then +-- return f_numeric(result) +-- elseif t == "string" then +-- return result +-- else +-- return tostring(result) +-- end +-- end +-- end +-- return "" +-- end + +local cache, n = { }, 0 -- todo: when > n then reset cache or make weak + +function metapost.runscript(code) + local trace = trace_enabled and trace_luarun + if trace then + report_luarun("code: %s",code) + end + local f + if n > 100 then + cache = nil -- forget about caching + f = loadstring(f_code(code)) + if not f and be_tolerant then + f = loadstring(code) + end + else + f = cache[code] + if not f then + f = loadstring(f_code(code)) + if f then + n = n + 1 + cache[code] = f + elseif be_tolerant then + f = loadstring(code) + if f then + n = n + 1 + cache[code] = f + end + end + end + end + if f then + local result = f() + if result then + local t = type(result) + if t == "number" then + t = f_numeric(result) + elseif t == "string" then + t = result + else + t = tostring(result) + end + if trace then + report_luarun("result: %s",code) + end + return t + elseif trace then + report_luarun("no result") + end + else + report_luarun("no result, invalid code") + end + return "" +end + +-- function metapost.initializescriptrunner(mpx) +-- mp.numeric = function(s) return mpx:get_numeric(s) end +-- mp.string = function(s) return mpx:get_string (s) end +-- mp.boolean = function(s) return mpx:get_boolean(s) end +-- mp.number = mp.numeric +-- end + +local get_numeric = mplib.get_numeric +local get_string = mplib.get_string +local get_boolean = mplib.get_boolean +local get_number = get_numeric + +-- function metapost.initializescriptrunner(mpx) +-- mp.numeric = function(s) return get_numeric(mpx,s) end +-- mp.string = function(s) return get_string (mpx,s) end +-- mp.boolean = function(s) return get_boolean(mpx,s) end +-- mp.number = mp.numeric +-- end + +local currentmpx = nil + +local get = { } +mp.get = get + +get.numeric = function(s) return get_numeric(currentmpx,s) end +get.string = function(s) return get_string (currentmpx,s) end +get.boolean = function(s) return get_boolean(currentmpx,s) end +get.number = mp.numeric + +function metapost.initializescriptrunner(mpx,trialrun) + currentmpx = mpx + if trace_luarun then + report_luarun("type of run: %s", trialrun and "trial" or "final") + end + -- trace_enabled = not trialrun blocks too much +end + +-- texts: + +local factor = 65536*(7227/7200) +local textexts = nil +local mptriplet = mp.triplet + +function mp.tt_initialize(tt) + textexts = tt +end + +-- function mp.tt_wd(n) +-- local box = textexts and textexts[n] +-- mpprint(box and box.width/factor or 0) +-- end +-- function mp.tt_ht(n) +-- local box = textexts and textexts[n] +-- mpprint(box and box.height/factor or 0) +-- end +-- function mp.tt_dp(n) +-- local box = textexts and textexts[n] +-- mpprint(box and box.depth/factor or 0) +-- end + +function mp.tt_dimensions(n) + local box = textexts[n] + if box then + -- could be made faster with nuts but not critical + mptriplet(box.width/factor,box.height/factor,box.depth/factor) + else + mptriplet(0,0,0) + end +end + +function mp.report(a,b) + if b then + report_message("%s : %s",a,b) + elseif a then + report_message("%s : %s","message",a) + end +end -- cgit v1.2.3